Skip to content
Dave Strus edited this page Aug 20, 2015 · 2 revisions

Logging In

Thus far, we've just been passing a single API key around, but there isn't a way for a new user to come to our app and use it in place of the Rails app. Each user should have their own notes, instead of just seeing yours.

Let's add a separate view and controller with a form to log someone in.

You'll notice that angular-seed gave us two sample views (view1 and view2), so feel free to look at those for how these files should be structured.

Add a new directory at app/login, and create two files inside named login.html and login.js, and fill them with this stuff:

app/login/login.html

<h3>Sign In</h3>

app/login/login.js

'use strict';

angular.module('notely.login', ['ngRoute'])

.config(['$routeProvider', function($routeProvider) {
  $routeProvider.when('/login', {
    templateUrl: 'login/login.html',
    controller: 'LoginController'
  });
}])

.controller('LoginController', [function() {

}]);

Now, let's inform the main Angular module in app/app.js of our new controller.

app/app.js

  'notely.notes',
  'notely.login'

And we need to add the new script to index.html.

app/index.html

<script src="login/login.js"></script>

Now you should be able to go to http://localhost:8000/app/#/login, and see our <h3>Sign In</h3>, big and green.

Let's add a login form.

LAB: Add a form to login.html with a field for login and password.

  • Extra credit: add a ng-submit form handler and $scope function.
    • Extra credit hint: Don't forget to change the controller function definition signature to inject the $scope dependency.

SOLUTION:

_app/login/login.html

<h3>Sign In</h3>
<form id="new_user" ng-submit="submit()">
  <p>
    <label for="username">Username</label><br>
    <input type="text" name="username" autofocus="autofocus">
  </p>
  <p>
    <label for="password">Password</label><br>
    <input type="password" name="password">
  </p>
  <input type="submit" name="commit" value="Sign In" class="btn btn-default">
</form>

app/login/login.js

.controller('LoginController', [function() {
  $scope.submit = function() {
    // do something
  };
}]);

This will complain that "$scope is not defined". Let's add the dependency:

(explain array syntax for minification)

.controller('LoginController', ['$scope', function($scope) {

Moving the NotesBackend service to app.js

There's a lot of things in our NotesBackend Service now, and there really isn't anything coupling it to our NotesController, so let's move it into app.js

Because the NotesController module tracks its dependency back to NotesBackend, we can still access it from the inside of the controller.

Refresh the page, and everything should still work—notes loading in the sidebar, adding and deleting notes, etc.

Add a function to get the API key

Nevernote provides a special way to login over the API that will return an API key if we authenticate with a valid username and password. Then we can use that key in subsequent requests.

Let's add the ability to hit that login endpoint, so we can present the users of our app with a working login page. Then we'll have a nice, multi-user app.

Let's implement the ng-submit on the login form, so when a user puts in their login/password, we attempt to fetch the API key.

Note the additional dependency injection in LoginController.

app/login/login.js

.controller('LoginController', function LoginController($scope, NotesBackend) {
  $scope.user = {};
  $scope.submit = function() {
    NotesBackend.fetchApiKey($scope.user, function(){
      debugger;
    });
  };
});

app/app.js

  var notes = [];
  var apiKey = '';

  this.getApiKey = function() {
    return apiKey;
  };

  this.fetchApiKey = function(userData, callback) {
    var self = this;
    $http.post(nevernoteBasePath+'session', {
      user: {
        username: user.username,
        password: user.password
      }
    }).success(function(data){
      console.log('got api key');
      apiKey = data.api_key;
      self.fetchNotes();
      typeof callback === 'function' && callback();
    });
  };

Hook the form fields up to the model:

  <p>
    <label for="username">Username</label><br>
    <input type="text" name="username" autofocus="autofocus" ng-model="user.username">
  </p>
  <p>
    <label for="password">Password</label><br>
    <input type="password" name="password" ng-model="user.password">
  </p>

We're passing in a callback function that want to use to redirect to /notes upon logging in.

To do this, we need to use the angular $location module, so let's add it as a dependency to LoginController and replace the debugger with $location.path('notes').

app/login/login.js

.controller('LoginController', function LoginController($scope, $location, NotesBackend) {
  $scope.user = {};
  $scope.submit = function() {
    NotesBackend.fetchApiKey($scope.user, function(){
      $location.path('notes');
    });
  };
});

Now, if we reload the page from '/login', and provide correct credentials, we'll be taken to our note form, but our API key won't persist and our notes won't be loaded.