Angular JS – shaping up (level 1)

1 Ramp up

http://campus.codeschool.com/courses/shaping-up-with-angularjs/level/1/section/1/video/1

So yesterday, out of the blue I was assigned a project on which I’ll be a mobile developer. We’ll be working with Angular as well as an Angular wrapper framework whose name I don’t remember, and I don’t have it typed out because it’s better to take notes by hand since apparently grownups think you’re always on Facebook otherwise. Everyone says Angular is incredibly difficult to learn.

What is Angular? It’s a front-end JavaScript framework. It speeds things up like this: usually when you click on a link, the page refreshes and downloads everything it needs next, like the html, images, etc. With Angular, clicking the link doesn’t refresh the page—it just downloads something it needs, like a bit of JSON—which saves a ton of time. That’s it!

1.1 Directives

<!DOCTYPE html>
<html>
  <body>
    . . .
  </body>
</html>
function hello(){
  alert('Hello, World!');
}

So as usual, we have two things: the HTML, and the JS. How do we get the HTML to run a JS function? Usually, I’d have some jQuery listener for something like “when the user clicks here, do this thing.” In Angular, we have directives.

“A directive is a marker on an HTML tag that tells AngularJS to run or reference some JavaScript code.”

<!DOCTYPE html>
<html>
  <body ng-controller="HelloController">
    . . .
  </body>
</html>
function HelloController(){
  alert('Hello, World!');
}

See what’s happening there? In the body tag we’re using ng-controller to tell the name of the function, and we’ve also renamed our function to HelloController. When we load the page, the alert should pop up. (It’s not doing that for me on CodePen, but let’s keeping moving through the tutorial and cry about that later.)

Anyway, the way that we’re attaching the function to the HTML is called binding — which is a term people throw around quite a lot.

1.2 Modules

Going forward, we’re using Angular (like, version 1.6.3 I think), and also Bootstrap. I’m just using the shortcuts built into CodePen to include them.

Modules are where we write parts of the Angular app, keeping each bit of functionality separate from the others. This keeps it clean and easy to test. Also, you can tell one module to have dependencies of other modules.

var app = angular.module('store', [ ]);

So this is us initializing the module, I guess! angular because that’s what we do. module because we’re creating a module. store is the name of the module. And the [ ] bit, that’s an empty array where if we had dependencies we’d include their names. Right now we don’t have any, but we still have to include this.

So now we have this module, but how do we run it? By adding a directive to the HTML that runs this module on page load. Like this:

<html ng-app="store">
  <body>
    hi
  </body>
</html>

See, the ng-app="store" refers to the store module we created a moment ago. And now, anything within the tag that has the directive on it (being the html tag) will be included within our Angular app.

1.3 Expressions

Expressions allow us to insert dynamic values into the HTML. Basically all the stuff you’d expect, like:

<p>
  The number after 2 is {{ 2 + 1 }}
</p> 

So to make Hello! 4 show up:

<html ng-app="store">
  <body>
    {{"hello! " + (1 + 3)}}
  </body>
</html>

2 Index HTML setup

2.1 Controllers

“Controllers help us get data onto the page. Controllers are where we define our app’s behavior by defining functions and values.”

So, back to our code:

var app = angular.module('store', [ ]);

First, they suggest wrapping everything in a closure, just because it’s good practice.

(function(){
  var app = angular.module('store', [ ]);
})();

And now we add this stuff…

app.controller('StoreController', function(){

  });

…which it asks us to note that the controller is attached to our app. By which they mean that the app is a variable we’ve created called app, right? Right. So when we see app.controller it indicates that we have our app module, and within the module is our controller called StoreController. The anonymous function in there is what will run when the StoreController is called.

So in whole, it’s:

(function(){
  var app = angular.module('store', [ ]);

  app.controller('StoreController', function(){

  });

})();

Next, we’re trying to get some data to show up on the screen—data that is currently contained in an object like this:

    var gem = {
      name: 'Dodecahedron',
      price: 2.95,
      description: ' . . . '
    }

Things are getting complicated fast. We’re going to toss this into the closure. It’s not going to be inside the app. But we do need to get its details inside our app somehow. So, we’ll assign a property of the controller to refer to it.

(function(){
  var app = angular.module('store', [ ]);

  app.controller('StoreController', function(){
    this.product = gem;
  });

  var gem = {
    name: 'Dodecahedron',
    price: 2.95,
    description: ' . . . '
  }

})();

See, this.product is now set to gem. We still need to get the data into the page. What does that even mean? Well, here’s placeholders of how we want it to look:

<html ng-app="store">
  <body>
    <div>
      <h1>Product Name</h1>
      <h2>$Product Price</h2>
      <p>Product Description</p>
    </div>
  </body>
</html>

And this is how it’ll look with our new code!

<html ng-app="store">
  <body>
    <div>
      <h1>{{store.product.name}}</h1>
      <h2>${{store.product.price}}</h2>
      <p>{{store.product.description}}</p>
    </div>
  </body>
</html>

In the div, we’re telling it the controller to refer to, StoreController, and then as store is telling it that the controller’s alias should be store. This is somewhat similar to creating an object, and then creating an instance of the object with a name, like var stephen = new Person() so that later we can say stephen.fallsOffSidewalkWhileTrainingFor10K. In our example, we can now use store to refer back to the this.product bit, which refers to gem, so that we can reach into gem and get those properties of the gem. Thus, store.product.name brings up name of the gem! And yes, it works in CodePen.

This sounds obvious, but just to be clear, the scope of the StoreController is only within the div that we placed it on. If we try to refer to store.product.name from outside the div, it won’t work.

3 Challenge

First I have to make a controller. This is what I type in:

var controller = angular.controller('StoreController', function(){

  });

You know why this is wrong? Because it’s just a free-floating controller! It’s supposed to be attached to the app!

app.controller = angular.controller('StoreController', function(){

  });

this doesn’t work. Maybe…

app.controller('StoreController', function(){

  });

There we go. We don’t have to assign it to anything. Now we have to attach it to the body tag.

<body ng-controller="StoreController as store">

Oh bam! First try! Now they’ve updated the code to include a gem, and for perspective:

(function(){
  var gem = { name: 'Azurite', price: 2.95 };
  var app = angular.module('gemStore', []);
  app.controller('StoreController', function(){

  });
})();

We need to assign it to the product property of the StoreController. So…

this.product = gem;

Yes! Lastly, how do we display it?

{{store.product.name}}

I did it!

4 Built In Directives

http://campus.codeschool.com/courses/shaping-up-with-angularjs/level/1/section/3/video/1

Guess what? There’s more directives. Yay I guess. So first we’re going to look at how to create a button. Edit the gem to make it so we can’t purchase it:

  var gem = {
    name: 'Dodecahedron',
    price: 2.95,
    description: ' . . . ',
    canPurchase: false
  }

DONE! jk you chump. We still have to add the button the usual way:

<button> Add to Cart </button>

4.1 ng-show

But the goal is to only show the button when the product is available for purchase. So we’ll use the ng-show directive to check if canPurchase is true or false.

      <button ng-show="store.product.canPurchase"> Add to Cart </button>

And now the button disappears since canPurchase is false! And it reappears if we mark it as true.

4.2 ng-hide

Likewise, we can hide rather than show things.

  var gem = {
    name: 'Dodecahedron',
    price: 2.95,
    description: ' . . . ',
    canPurchase: true,
    soldOut: true
  }

We’ve altered the HTML a little bit so that the body tag has the ng-controller on it. And inside it is a div that will only show the product if it’s not sold out.

<html ng-app="store">
  <body ng-controller="StoreController as store">
    <div>
      <h1>{{store.product.name}}</h1>
      <h2>${{store.product.price}}</h2>
      <p>{{store.product.description}}</p>
       Add to Cart 
    </div>
  </body>
</html>

That is, show if NOT the product is sold out is true. It’d be less awkward to just say hide if the product is sold out is true.

<div>

4.3 ng-repeat

Next, we’re going to expand the store to have multiple items.

var gems = [
    {
      name: 'Dodecahedron',
      price: 2.95,
      description: ' . . . ',
      canPurchase: true
    },
    {
      name: 'Pentagonal Gem',
      price: 5.95,
      description: " . . . ",
      canPurchase: false
    }

Since this is an array, we can refer to objects like store.products[1].description, etc. – but that would require us to repeat what we type in for each product. So instead we’ll use the ng-repeat directive, like this:

<div>
      <h1>{{product.name}}</h1>
      <h2>${{product.price}}</h2>
      <p>{{product.description}}</p>
       Add to Cart 
</div>

Which iterates through the products and displays both. The format is like a for in loop where store.products is the array, and product is the iteration of it.

5 Exercise

http://campus.codeschool.com/courses/shaping-up-with-angularjs/level/1/section/3/not-for-sale

Now I have to do this stuff by memory. First, to make the button only appear if canPurchase is true.

<button ng-show="store.product.canPurchase">Add to Cart</button>

Yes! And now to hide the product if it’s sold out.

<div ng-hide="store.product.soldOut" class="product row">

Hooray!

Next, we have to deal with not a single gem product, but an array of gems. In the controller, first I tried:

products = gems;

which didn’t work because it’s not supposed to just be a variable…it’s a property of the controller instance! So…

this.products = gems;

Finally, I have to do a repeat. First I tried:

ng-repeat="product in products"

which didn’t work because…well, I don’t know. But it makes sense to me that it would! So I’ll try to be more specific:

ng-repeat="product in app.products"

which also doesn’t work. I’m thinking it has to do with app being a way of distinguishing things inside the JavaScript file, but not within the HTML. Okay, so where is the products? It’s in the app. Where in the app? In the controller. Where in the controller? Right there. Just, there. So what is the controller called? StoreController. Well, in body we say that it’s called store–so, we’d look at store.products to find the products.

<div ng-repeat="product in store.products">
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s