Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

backbone.js ajax calls

I 'm learning Backbone.js for a new app I'm building. I need to perform an AJAX call(REST SERVICE) to authenticate.

Where is the correct place for this call? In the Model, View or somewhere else? specifically related to Backbone.js MVC model.

<html>
<head>
<script src="lib/jquery-1.6.1.min.js"></script>
<script src="lib/json2.js"></script>
<script src="lib/underscore-min.js"></script>
<script src="lib/backbone-min.js"></script>   

<script language="javascript">
      $(function(){
         var LoginView = Backbone.View.extend({
          el: $("#login-form"),

          events: {
            "click #login": "login"
          },

          login: function(){
              alert("Hello");
           }
        });

        window.LoginView = new LoginView();
      });
    </script>   
  </head>
  <body>
    <form action="/login" id="login-form">
      Username: <input type="text" id="username"><br>
      Password: <input type="password" id="password"><br>
      <button id="login">Login</button>
    </form>
  </body>
</html>
like image 332
John Cooper Avatar asked Jul 04 '12 15:07

John Cooper


2 Answers

Create an authentication Model, that stores the post state (username, password, remember me) as well as the response state (login failed, login accepted)...

App.Model.authentication= Backbone.Model.extend({
    defaults: {
        Username: "",
        Password: "",
        RememberMe: false,
        LoginFailed: false,
        LoginAccepted: false
    },
    url:"api/authentication"
});

Update the View to use the model:

   $(function () {
    var LoginView = Backbone.View.extend({
        model: new App.Model.authentication(),
        el: $("#login-form"),
        events: {
            "click #login": "login"
        },

        login: function () {
            this.model.save({username: this.$el.find("#username"),
                password: this.$el.find("#password")}, {
                success: function () {
                    /* update the view now */
                },
                error: function () {
                    /* handle the error code here */
                }
            });
        }
    });
}

);

Calling Model.Save() will issue a post request to the server, although in this instance on the server you're not actually saving anything, but check the credentials and sending back an object with the same model, but with the "LoginAccepted" field set appropriately.

Don't implement custom JQuery AJAX Posts - Its not in the spirit of backbone, which handles it all for you under the hood via its REST interface.

More details on the REST interface and the various REST Actions and URLS that backbone uses here: http://codebyexample.info/2012/04/30/backbone-in-baby-steps-part-3/

One more thing on the AJAX vs model.save() debate. If your application was a stateless chat room like IRC - which sends messages to other users in the chat room but doesn't save the messages centrally... would you throw away all of backbone's REST functionality and re-implement them with custom AJAX calls because you're not ACTUALLY 'saving', you're really just 'sending'. That would cost you a huge amount of work to re-implement functionality that's already there, just because of semantics. Always read model.save() as model.post() - its not just for saving - its for sending.

like image 101
reach4thelasers Avatar answered Oct 21 '22 06:10

reach4thelasers


You always start in the view because your DOM interactions (incl. form submits) happen in views.

Then, if I were you, I would add a custom method to the User model, and call the method from the view. The login method does not exactly fit with native Backbone sync as you're not trying to add / update / retrieve anything (mind that you DO NOT want to load user password or password hash from the server for security reasons). So you do a regular Ajax call without calling Backbone fetch(). So, here you go:

var UserModel = Backbone.Model.extend({
  ...
  checkLogin: function(name, password) {
    var self = this;
    $.post('/login', { name: name, password: password }, function(data) {
      self.set(data); // data should be in JSON and contain model of this user
    }, 'json').error(
      self.trigger('loginError'); // our custom event
    );
  }
});

And the view:

var UserView = Backbone.View.extend({
  events: {
    'click .login': 'loginSubmit'
  },

  initialize: function() {
     _.bindAll(this, 'loginSubmit', 'loginSuccess', 'loginError');
     this.model.bind('change', this.loginSuccess);
     this.model.bind('loginError', this.loginError);
  },

  loginSubmit: function() {
    var name = 'username', // you get it from some element
        password = '***'; // you get it from another element
    this.model.checkLogin(name, password);
  },

  loginSuccess: function() {
    alert ('You have been logged in');
    console.log(this.model); // should log loaded user model
  },

  loginError: function() {
    alert ('Problem with login');
  }
});

Make sure you pass the UserModel instance to the UserView instance, e.g.:

var userModel = new UserModel,
    userView = new UserView({ model: userModel });
like image 28
mvbl fst Avatar answered Oct 21 '22 06:10

mvbl fst