Showing posts with label learn MEAN stack. Show all posts
Showing posts with label learn MEAN stack. Show all posts

Sunday, April 6, 2014

Angular JS - Directives

I've spent a lot of time recently mucking around across the whole MEAN stack. MEAN.io includes a lot of added tools, which is cool, but it can be distracting. So, I'm going to refocus now that I'm comfortable with the entire stack. No, I'm not an expert yet, just comfortable. Documenting almost every line of the code really helped to understand what was going on as did working on my own goofy project. I made a time/task tracking system to use at work. That was a good way to let the MEAN stuff sink in, but eventually the learning slowed and I started to focus on the business logic of what I was doing. That's fun, but now it's time to get back to deliberate study.
So, back to Angular. The first thing we'll focus on is directives.

Directives

There are lots of built in directives. Read over this cheat sheet and learn how they work.

How Directives Work

Directives identify parts of the DOM that should have special Angular goodness. These parts are picked up by the compiler (see $compile).
Directives are attached to modules using the directive method of the $compileProvider.
What is a directiveFactory?
The directive factory is executed the first time the compiler matches the directive. The function returns an object that tells $compile (see Directive Definition Object) how the directive works.

Making Custom Directives

A Simple Example

angular.module('foo').directive('pointless', function () {
    return {
        template: 'some text to show in directive'
    };
});

Isolate Scope

The purpose is to isolate the scope within the directive from the scope outside the directive. This is done with the scope option of the directive definition object.
The isolate scope does not inherit from the parent scope.
The scope option maps outer scope values to inner scope values in three different ways.
  1. @ - map from directive's attributes as strings
    • innerFoo: '@' The inner scope's innerFoo value comes from the directive's inner-foo attribute.
    • innerFoo: '@outerFoo' The inner scope's innerFoo value comes from the directive's outer-foo attribute.
    • Any interpolated values (defined in the directive's attribute to pull from the outer scope) will still populate from the outer scope.
  2. = - map from parent scope property to isolate scope property
    • innerBar: '=' - The inner scope's innerBar value is bound to the outer scope value indicated in the directive's inner-bar attribute.
    • innerBar: '=outerBar' - The inner scope's innerBar value is bound to the outer scope value indicated in the directive's outer-bar attribute.
    • Values bound like this will update each other. Changes in the isolate scope will be reflected in the outer scope and vice versa.
  3. & - map an expression to be executed in the outer scope
    • This follows the same pattern as above, though I can't think up an example.

References

Thursday, February 20, 2014

Make the MEAN Boilerplate Your Own

I took my own advice and decided to make a new project. Here are my notes for adding a new page to the boilerplate.

  1. Add a reference to the HeaderController in /public/js/controllers/header.js in $scope.menu
  2. Add a route for the new link's path in /public/js/config.js. (hmm... they use $stateProvider instead of $routeProvider) Include a templateUrl.
  3. Create a template in /app/public/views/.
    • note - They use data-ng-foo for their directives. data- is ignored by Angular JS. This is just for html validation purposes. When in Rome...
    • Add a controller to the template. Cry when you refresh because Angular is sad.
  4. Create a module to attach the controller to in /public/js/app.js. Since they've already got everything hooked up to the 'mean' module, just dangle from that. angular.module('mean.notes', []);

I made a mistake at this point (metioned at the end). Next time, I won't. Learning is fun!


  1. Create the controller in /public/js/controllers/notes.js. Attach the controller to the module created above.
    • You can pretty much copy the first line of the definition from articles.js, just remove the Articles injection and name the controller correctly.
    • Add a $scope variable to the controller ($scope.foo = 'bar';) and in the view (step 3 above - {{ foo }}) so you can be assured it's all working.
  2. Add the controller reference so Angular won't cry anymore. Look for Application Controllers in /app/views/includeds/foot.html.
  3. Restart the server.

Dang

:( OK, everything seems hooked up, but the controller isn't found for some reason. I added a breakpoint in the new controller, and it is being loaded. I kept getting

Error: [ng:areq] http://errors.angularjs.org/1.2.13/ng/areq?p0=NotesCtrl&p1=not%20a%20function%2C%20got%20undefined

It turns out, although we set up a namespace and defined everything, the new controller was never injected into the main app's "mean" module. This was not noticed for a bit because of the in my opinion bad formatting that caused the dependencies to go way off the page.

tl;dr

Format the verbose injection so you can see everything!

You can't just define a module and add a reference to the script. You have to inject it!

Wednesday, February 19, 2014

Plugging Angular Seed Project into MEAN Boilerplate

So, I've got a little app and I want to start using REST methods for persistence. At this point, the app is just Angular with no backend, using localStorage like a database. Eventually, I'll be getting into Node, Express, and MongoDB, so why not use the MEAN boilerplate to whip up the backend? Just a little tinkering to get the services I need up and then I'll be free to start experimenting with $http and $resource.

I pulled down the boilerplate (instructions here) and moved my files to the corresponding directories. Some of the files didn't match up exactly, so I copied the code the corresponding boilerplate files. After shuffling a few things around and changing commenting out a few unneeded lines, I expected to be up and running.

No Grunting

I'd used grunt to run the MEAN apps I'd played with before, so I tried it again.

grunt

Grunt does all sorts of cool things like linting the app, running test suites, and monitoring for file changes. This last thing is super cool because, as we'll discover when we start working with Node and Express, changes to basically anything other than templates requires restarting the server. Grunt watches for these and restarts automatically - even triggering a browser refresh - so we don't have to.

Anyway, so when I reflexively started the server with grunt, I got a whole bunch of errors from tests, JSLint, and frankly a lot of shit I didn't even look at. I figured it would still work, I'd just have to go back and clean up a few things. Unfortunately, that was not the case.

I couldn't get anything to serve up in the browser. (Yes, I did note that the Angular JS seed serves on port 8000 and MEAN uses 3000). In order to get anything to the browser, I had to skip grunt and run the server manually.

node ./server.js

So Many Errors

The browser console (I shouldn't have to specify, but "the browser" is always Chrome) had a ton of errors, some more cryptic than others. I figured out that I could glean from the callstack or url where the error was emanating from or what it was looking for. Eventually I was able to track everything down and - keep in mind, my objective is just to get a backend up - comment a bunch of crap out. It's ugly, but it's a throw-away. Stop judging me.

Why Aren't You Updating?!

A lot of the resources I didn't care about anymore were specified in the node view in /app/views/includes/foot.html. (I thought these were Jade templates the last time I used this.) For some reason, most definitely user error, no matter what I changed or how often I cleared the browser's cache, the changes didn't show up. Honestly, I don't remember what I did to fix it and I may have the series of events backwards. Now that I write it, I think initially grunt may have worked despite the errors and it was caching the pages. Either way, I ended up starting the server as described above and restarting it after every change (ctrl + c x 2 to stop server). It was ugly and painful, but eventually I started to see my first app shining through.

Easy Street DETOUR

The final step of my plan was to delete the .git directory inside my initial app, which was lost somewhere amongst the MEAN files, reinitialize the repo, git add ., add a commit message, and check it in. That went well until the last part.

Apparently, Git's a little smarter and more cautious than I am when I only have 3 minutes left for lunch. It rightly told me that everything was all fucked up - I could be off with the wording - and it was not safe for me to just check everything in (see non-fast-forward errors). Since I don't have anyone else on my team and I was feeling particularly rushed, I forced git to accept it, consequences be damned.

git push -u origin master --force

This was dirty and careless, but I got everything back into my remote branch before lunch ended, so I considered it a success. A just remembered, there were a few hiccups while shuffling my files around that I omitted. This was probably due to having multiple directories named "notes". It came in handy to reject all the changes I'd made, several unintentionally, so I could start over. The useful command for that is:

git checkout -f

This is basically a big "undo" for all uncommitted changes in the current branch. Again, very heavy-handed, but I'm not focused on the minutia of git right now.

tl;dr

The lesson is, don't try to merge an existing project into the MEAN boilerplate in the last half of your lunch break. If your directives and services and whatnot are portable (they should be), just move those and recreate the views. Also, don't try to trick git; create a new repo.

Monday, February 17, 2014

Getting Started

Read the Bible

Read JavaScript: The Good Parts.  When you're done, read it again.  You've probably read it before, so read it one more time.  Things that made your eyes gloss over the first couple times will be much easier to understand this time.  It's not that I'm a huge Crockford fan, but this is the Javascript book.  You may have discovered the same patterns on your own, but it will reflect negatively on you if you call memoization "method result caching" or some other weird phrase you coined.

It's easy to get submerged in whatever frameworks you've been working in and forget about the nuts and bolts.  Since we want to jump into the cutting edge of Javascript awesomeness, we'd better brush up on the mechanics.  Simply being able to drive does not make you capable of building a better car.

I got the book from Google and have started reading it a few pages at a time on my phone.  Instead of compulsively checking email in the elevator to impress the other people doing the same, I'll just read a page.  I may also revisit JavaScript Design Patterns, though I remember it being a little too verbose and covering much of the same content.

Leave Windows

The best way to learn Spanish is to wake up somewhere in Mexico, right?  So, I'm assuming the same goes for Linux.  Learning *nix has been on my to-do list for a decade, but it never seemed very urgent.  Nuts to that.  I spent a couple hours backing things up, then switched my computers to Ubuntu.  After the initial shock - Oh, god.  What are the shortcut keys?! - the difference isn't severe.  A small piece at a time, I'm learning about the environment, terminal especially.  The great thing about JS is it's interpreted; all we need is a text editor.  As a bonus, all the cool stuff we're going to be doing assumes that you're on Linux or OSX.  Steps in tutorials for Windows users are rare and a huge headache.

When I need to figure something out, I look up how to do it.  Eventually, I'm too lazy to keep Google-ing the same thing, so I just remember it.  Remember, once, sometime in ancient history, you didn't know Windows either.

Get Social

It is assumed that you have a Github account.  You should, and you should commit every day.  I haven't run in months, but I've committed (pun allowed, not intended) to show activity on Github every day.  I'm making it part of my routine.  I started just storing my own work, but now I'm starting to become interested in others'.  Star projects you're into and look at pull requests.  It's nice to see what other people are writing, and the more exposure the better.  Eventually, I'm going to look for some low-hanging fruit and take a stab at a pull request.  I'm sure there's a typo out there I can fix for starters.  Once I've been through that process, I'll aim bigger.

In addition to Github, I've started taking the time to become active on Stackoverflow.  This is like trivia and can be a good break from constant cramming.  Corny, yes, but it also makes me feel kind of nice to help lost noobs, since I have benefited from SO many, many times.

Most employers now research potential hires online, so it can't hurt to increase your presence on these major sites.  As a side-effect, some of the culture, language, customs, and technology is bound to rub off.  Unless you want people judging you based solely on Facebook, get on Github and Stackoverflow.  For me, these two are Facebook.

Assimilation Complete

We are now reading, computing, and social networking like ducks.  Let's start learning how to swim.


Appologies to GN's: I realize changing from talking about myself, us, you, then us, the x repeatedly is terrible.  I am embarrassed to a degree, but this is basically a journal.  If I take on the burden of proper editing and good writing, this blog will quickly become a chore and will die.