Question

I have changed the official AngularJS documentation to use Firebase (the phone tutorial).

This is the router of my app:

angular.module('phonecat', ['firebase']).
 config(['$routeProvider', function($routeProvider) {
 $routeProvider.
      when('/phones', {
        templateUrl: 'partials/phone-list.html', 
        controller: PhoneListCtrl,
        authRequired: false,
        pathTo: '/phones'
      }).
      when('/phones/:age', {
        templateUrl: 'partials/phone-detail.html',
        controller: PhoneDetailCtrl,
        authRequired: true,
        pathTo: '/phones/:phoneId'
      }).
      when('/login', {
        templateUrl: 'partials/login.html',
        controller: LoginCtrl,
        authRequired: false,
        pathTo: '/login'
      }).
      otherwise({
        redirectTo: '/phones'
      }); }]);

This is how the controller looks like - but it is probably incorrect. The login function gets called, however I'm not sure what to do next. How should I redirect the user from the login page to the phone-detail.html page?

'use strict';

function PhoneListCtrl($scope, angularFire, angularFireAuth) {
  var url = 'https://<link>.firebaseio.com/';
  var promise = angularFire(url, $scope, 'phones', []);
  angularFireAuth.initialize(url, {scope: $scope, name: "user"});
}

function PhoneDetailCtrl($scope, $routeParams, angularFire, angularFireAuth) {
  var url = 'https://<link>.firebaseio.com/' + $routeParams.age;
  angularFireAuth.initialize(url, {scope: $scope, path: "/login"});
  $scope.$on("angularFireAuth:login", function(evt, user) {
    var promise = angularFire(url, $scope, 'phone', {}); 
  });
  $scope.$on("angularFireAuth:logout", function(evt) {
    console.log("you are logged out.");
  });
  $scope.$on("angularFireAuth:error", function(evt, err) {
    console.log(err);
  });
}

function LoginCtrl($scope, angularFire, angularFireAuth) {
  var url = 'https://<link>.firebaseio.com';
  $scope.form = {};
  $scope.login = function() {
    console.log("called");
    var username = $scope.form.username;
    var password = $scope.form.password;
    angularFireAuth.login('password', {
        email: username,
        password: password,
        rememberMe: false
      });
  };
}

The login.html looks like this:

<input type="text" name="username" ng-model="form.username"><br>
<input type="text" name="password" ng-model="form.password"><br>
<button name="login" id="login" ng-click="login()">login</button>

What I'd like to achieve is this:

  1. List all the phones
  2. If the user clicks to get the details of one of them, check if they are authenticated
  3. if yes, show the phone details -- if not, redirect them to the login page.
  4. After logging in, redirect them to the phone detail view.

I'm struggling with points 3 and 4.

Update

After the comments from Anant -- I found something very interesting. I added a few debug msgs to angularFire.js and for the time being I changed the authRequired from true to false in my controller above.

If navigate to /phones - I get a list returned back from firebase as expected. Inside _loggedIn() I added console.log(user) which returns a user object (also, inside initialise I added a debug statement: https://github.com/firebase/angularFire/blob/master/angularFire.js#L437 -- both confirm that I have a valid user, already logged in.

If I then click on an item, I get what I expect - the username and the actual page loads (see the html below). If I refresh that page (http:///phones/#/0) I get the right page again and in the console, I still see a valid user object, indicating that the user is still logged in

Here's the HTML for both phone-list.html and phone-details.html:

phone-list.html
<div class="container-fluid">
    <div class="row-fluid">
      <div class="span4">
        <!--Body content-->

        <ul class="phones">
          <li ng-repeat="phone in phones">
            <a href="#/phones/{{phone.age}}">{{phone.id}}</a>
            <p>{{phone.snippet}}</p>
          </li>
        </ul>
      </div>
    </div>
  </div>

phone-detail.html
<span ng-show="user">
  {{user.email}} | <a ng-click="logout()">Logout</a>
  you are look looking at {{ phone.name }}
</span>
<span ng-hide="user">
  login pls!
</span>

And a snippet from the JSON (that is now part of Firebase):

[
{
    "age": 0, 
    "id": "motorola-xoom-with-wi-fi", 
    "imageUrl": "img/phones/motorola-xoom-with-wi-fi.0.jpg", 
    "name": "Motorola XOOM\u2122 with Wi-Fi", 
    "snippet": "The Next, Next Generation\r\n\r\nExperience the future with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb)."
}, 
{
    "age": 1, 
    "id": "motorola-xoom", 
    "imageUrl": "img/phones/motorola-xoom.0.jpg", 
    "name": "MOTOROLA XOOM\u2122", 
    "snippet": "The Next, Next Generation\n\nExperience the future with MOTOROLA XOOM, the world's first tablet powered by Android 3.0 (Honeycomb)."
}...etc

If I then change the authRequired back to true - and if the user object is available, then I get an endless loop of page loads - first it's /login then it gets automatically redirected /phone/0 and immediately back to /login again, and this happens until the browser crashes.

Update 2

After adding some further debug lines and poking around with the code I've come up with this solution:

add the initialisation to the LoginCtrl:

var url = 'https://<link>.firebaseio.com/'; 
angularFireAuth.initialize(url, {scope: $scope});

In angularFire.js, I commented out lines 406 and 407:

//this._redirectTo = null;
//this._authenticated = false;

Appended the code around line 438, essentially I added this._authenticated = trueand this._redirectTo = $route.current.pathTo - as well as this._authenticated = false to the else statement.

var client = new FirebaseSimpleLogin(this._ref, function(err, user) {
  self._cb(err, user);
    if (err) {
      $rootScope.$broadcast("angularFireAuth:error", err);
    } else if (user) {
        this._authenticated = true;
        this._redirectTo = $route.current.pathTo;
        self._loggedIn(user)
    } else {
        this._authenticated = false;
        self._loggedOut();
    }
  });
  this._authClient = client;
},

The only scenario where this does not work is when a user is logged in and I navigate to http://<host>/#/login - the $route.current.pathTo will be equal to /login and at the moment I'm not 100% sure how to overcome this. Any thoughts on this Anant?

Was it helpful?

Solution

I have opened Issue 72 on GitHub: https://github.com/firebase/angularFire/issues/72

The interim solution for the time being is to modify angularFire.js and:

Remove the following two lines from the initialise function:

this._redirectTo = null;

this._authenticated = false;

Modify angularFire.js around line 438 (the declaration of var client) to read the following:

var client = new FirebaseSimpleLogin(this._ref, function(err, user) {
  self._cb(err, user);
    if (err) {
      $rootScope.$broadcast("angularFireAuth:error", err);
    } else if (user) {
        this._authenticated = true;
        this._redirectTo = $route.current.pathTo;
        self._loggedIn(user)
    } else {
        this._authenticated = false;
        self._loggedOut();
    }
  });`
  this._authClient = client;
},

As mentioned above this fixes nearly everything - the only problem seems to be that if there's a valid user object (i.e. someone is logged in) navigating to /login should redirect the user to another page, at the moment nothing happens. The GitHub issue should have further information on this hopefully soon.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top