AngularJS: We have an Error

If you’re like me and find AngularJS hard to understand, then debugging can be even more difficult. Since I’ve been running into them quite often, I’ve improved upon my abilities to decipher the cryptic errors that pop up in the console. Most of the time, these pesky errors are of the simple human variety: as in, you probably misspelled a word or forgot to add a dependency. In my case today, it happened to be loading my scripts in the correct order. Here’s the error I was receiving:

screen-shot-2017-01-25-at-2-39-47-pm

Lovely, right? Okay where to start. Well, of course now I know, but I’ll take you along through my thought process. First, I checked app.js to see if there were any typos. Nope, sorry sir, move along. Second, as you can see from the error above, the last line says PostService.js.15. So I’ll check out that file, and on line 15 the module is correctly stated. The only other place it could be (since my app is so small) is my index.html file. Let’s head on over there. My scripts were loaded as follows:

screen-shot-2017-01-25-at-2-51-46-pm

These were loaded just before the closing body tag. See anything troubling? Well, I have a service and a controller loading before my app.js file. So when the scripts are loading, my module hasn’t been created yet. Simple, yet frustrating. So just remember to load your app.js script before your other js scripts (and after your angular.js scripts). Oh Angular..some day we’ll be friends.

screen-shot-2017-01-25-at-3-18-47-pm

Advertisements

AngularJS & Rails: No Helpers:(

Angular is a front-end framework and is used for speed and asynchronous page loading (no page reloading on each request). Which means much of the helpers we rely upon in Rails are deemed useless. This can be hard to take for someone new to a front end framework like myself. But, alas, life must go on! The biggest obstacle for me so far is not being able to use the Flash Messages helper provided by Rails. What to do?

There are a few options out there on github that you can use. After trying a few different repos on Github which gave me a plethora of errors, I came across Toastr. It appealed to me right away because of it’s simplicity. I ran into one small bug (which was on my side), so I thought I might share.

The Set Up

screen-shot-2017-01-19-at-5-02-44-pm
First, to install Toastr, you can use Bower or npm. Next, copy the css and js files from the repo into your Asset Pipeline  – app/assets/stylesheets and app/assets/javascripts respectively. This will auto-rails-magically make the files available to use (as long as you //= require your trees *= in your application.js/css files). Now we can set up a factory in Angular.

The Chocolate Cheese Toaster Factory

screen-shot-2017-01-19-at-7-18-05-pm

Hey you…can you pass the butter, please?

Here we have set up a factory (we can just as easily use a service), which returns an object. Note that we also have access to other methods such as info and warning, but I only needed success and error for my project. When we call our toaster from a controller, we can give any text we’d like the user to see as an argument. I needed an error message telling a user that they couldn’t upvote a post more than once.


This Isn’t Going to Hurt, I Swear

We can then inject our toaster (factory) into any controller we’d like, then we have access to our success and error calls.

 

screen-shot-2017-01-19-at-8-20-51-pm
We’re injecting our toaster factory into our Main Controller. Now we can use it in any function we see fit. As I mentioned earlier, I needed to show the user an error if they tried to vote more than once on a post. By using a basic conditional statement with a some method on the array I could check for previous voters. I created a private function called voteChecker that checks the an upvoted posts user_id against the current_user $scope.user.id (I had to use inject the controller with Auth from the angular-devise gem for this).

screen-shot-2017-01-19-at-8-30-10-pm

By using the voteChecker function as the callback for the some method, we can check if any of the previous upvotes were from our current_user (I know, I know). However, the some method will return true if our array is empty, so we have to check that too. If the some method returns true && our upvoted_posts array’s length is not zero, then we have ourselves a two-timer and get to yell at them:) If, however, the challenge is passed, then we get to use our posts service (which I’m not going to delve into) to upvote our post. Very nice!

The Bug

I almost forgot! After doing everything above, I was getting a strange error:

TypeError: Cannot read property ‘extend’ of undefined

Crap! Well after a little Stack Overflowing it turned out that I was requiring jQuery after Angular in my application.js file. Once I put it before angular, everything was all good. NOTE – the same goes for if you’re including links or script tags referencing the angular and jQuery files from your application.html file. Well, all this toaster talk has made me quite hungry, so I think I’ll end here. If you ever need a flash message in your life and you’re using a front end framework, check out toastr!

 

Stumbling Through Angular: Routes!

AngularJS can be quite difficult to comprehend. Today, while trying to follow along Udemy’s Angular tutorial (hosted by Tony Alicea – it is great by the way!), I ran into some trouble with routing. Angular has built in routing that is very useful, but when things don’t work as you think they should, it can be frustrating. Every programmer in the world has been there. Although banging your head against the wall for a few hours can be quite fun, sometimes it’s best to go take a walk. When you come back, all of a sudden the problem is obvious. In my case, I was really trying to do something simple, but I just couldn’t get it to work.
screen-shot-2017-01-03-at-8-21-56-pm
Setting up the routing is fairly easy, once you  know the basic syntax of Angular. To the left is the file structure for my primitive app. I just wanted to have a main index page with two links. Simple right? Well a few hours later, yes…very. But if I can save anyone else a little time then it was all worth it. First off, we have to let Angular know that we want to use routing in our app. We can either use a link from Angularjs.org or we can download the node modules directly into our app, which I did. In both cases, we add it to our app with a script tag in index.html file. To download, in your terminal type:

‘npm install –save angular-route@1.6.1’

The numbers at the end represent the version of Angular you are running. If you’re not sure which version you’re running, open up package.json and you’ll find it in there.

Now we can add the script to our index.html file (it must be under your angular.js script!).

screen-shot-2017-01-03-at-8-39-31-pm

Note that these are all relative to my index.html file which is in the top of my file directory. Next, in app.js we let Angular know we want to rely on ngRoute. We do this in our module setup like so:

screen-shot-2017-01-03-at-8-32-02-pm

Here we are setting our module up and telling it to include ‘ngRoute’. Now we can use the routing capabilities. I set up two simple controllers to handle the two different links:

screen-shot-2017-01-03-at-8-50-42-pm

Here I’m using the array syntax which basically allows you to minify your files when you go to scale without any hiccups. But that’s for another blog post.  In the body of my index.html file I have two links and a div with a built in Angular directive.

‘ng-view’ tells Angular to look at the url screen-shot-2017-01-04-at-9-04-33-amand use the correct template that we set up with our routing. For this exercise I daisy chained all of my controllers and the like to my main module, but for bigger applications we’d have them in their own separate files. Now all we have to do is hook up our routing and we’re all set…

screen-shot-2017-01-04-at-10-16-54-am
So when we go to our main route, ‘/’, we’re expecting our ‘ng-view’ to summon up our main.html file with our $scope attached to our mainController. Welp, that didn’t work. I was getting a ‘404 (Not Found)’ error in my console. My main.html file couldn’t be found.

After searching stackoverflow.com for a  while I thought I found my answer. You can check out this stackoverflow exchange to see what I thought might be going on. Here’s the gist of it…

screen-shot-2017-01-04-at-10-50-12-am

So I tried a few of their solutions and also tried changing the templateUrl to no avail. After taking a much needed walk, I realized that I was giving the location of my html file relative to my app.js file and not my index.html file. So once I changed the templateUrl to reflect that, everything was groovy!

screen-shot-2017-01-04-at-10-27-00-am

Final app.js file

Unfortunately, something was still off when I clicked my links in the browser. The first link was working fine, but the second wasn’t doing anything. Well, technically it was changing the url in the browser, but nothing was going on in my terminal behind the scenes or changing on the web page. The main url is on the left and second link/url on the right.

Something funky was going on with the second link. There were a few characters that were being added – ‘#%2’ – before ‘second’. When I went directly to the ‘/second’ url, everything was cool – my page loaded up correctly. So what was the deal with the extra characters? What’s up Angular?!? I tried changing my href in index.html to include the bang before the ‘/second’. screen-shot-2017-01-04-at-10-55-15-am

And it worked! YAY! I still didn’t know what the heck was going on, but it worked! I thought that Angular, by default, adds a hash to url’s, which is why I included them in the first place. I didn’t know about the bang though. It’s called a hashbang, by the way. There are ways to beautify url’s in Angular, but I’ll leave that to more seasoned Angularites. I hope this will help someone out there! May your journey be smooth and remember – everyone stumbles! Just get back up and keep trekking#!