1

I have implemented a simple login system using Backbone.js.

I am attempting to pass the username and password using HTTP POST method to the Controller class which handles the user authentication.

public function sessions() {
    if ($this->input->server('REQUEST_METHOD') == 'POST') {
        $this->login();
    } elseif ($this->input->server('REQUEST_METHOD') == 'GET') {
        $this->index();
    } elseif ($this->input->server('REQUEST_METHOD') == 'DELETE') {
        $this->session->sess_destroy();
        $this->index();
    }
}

The Backbone.js code segment:

$(document).ready(function() {

    var Session = Backbone.Model.extend({
        url: function() {
            var link = "http://<?php echo gethostname(); ?>/reddit/index.php/welcome/sessions";
            return link;
        },
        defaults: {
            username: null,
            password: null
        }
    });

    var model = new Session();

    var DisplayView = Backbone.View.extend({
        el: ".complete",
        model: model,
        type: 'POST',
        initialize: function() {
            this.listenTo(this.model, "sync change", this.gotdata);
        },
        events: {
            "click #signin": "getdata"
        },
        getdata: function(event) {
            event.preventDefault();
            var username = $("input#username").val();
            var password = $("input#password").val();
            this.model.set({ username: username, password: password });
            this.model.fetch();
        },
        gotdata: function() {
            console.log(this.model.get('username'));
            console.log(this.model.get('password'));
            $("#base-nav").load(location.href + " #base-nav");
            $("#signin-form").load(location.href + " #signin-form");
        }
    });

    var displayView = new DisplayView();
});

I have used the type attribute currently to define the HTTP method type POST. But this does not seem to work as only GET requests can be observed using the developer console.

It has to be noted that when I remove event.preventDefault(); which prevents page reload upon clicking a link (Preventing full page reload on Backbone pushState) the POST request seems to be successfully delivered to the back-end although the page reload prevents the intended target behavior.

How do we easily send data using POST request with Backbone.js?

Community
  • 1
  • 1
Chiranga Alwis
  • 1,049
  • 1
  • 25
  • 47
  • Where did you see that there's a `type` property on Backbone views? – Emile Bergeron Jan 11 '17 at 23:04
  • It looks like you're confusing class properties with some function options. – Emile Bergeron Jan 11 '17 at 23:27
  • I saw it here. http://stackoverflow.com/questions/21771089/backbone-js-getting-data-on-post-request – Chiranga Alwis Jan 12 '17 at 05:45
  • 1
    Ok, you're definitely confusing the `fetch` option object with the view class properties. There's no `type` option for view. The `type` is an option of [jQuery's `ajax`](http://api.jquery.com/jquery.ajax/) function, which is used in the background by Backbone. – Emile Bergeron Jan 12 '17 at 14:14

1 Answers1

5

You're using this.model.fetch(); which serves to retrieve data. It makes a GET request by default and doesn't send any data in the body or in the query string.

When trying to find options and functions, use the documentation. The Backbone source code is also short and easy to follow.

Quick fix

Use save

this.model.save();

To enforce POST request, like if the model has an ìd set when you're already signed in and only want to validate the login again, use the type option to avoid PUT or PATCH request when Backbone determine it's an update and not a create call.

this.model.save(null, { type: 'POST' });

The options passed to save, fetch, create and destroy, all of which use Backbone.sync, are also passed to jQuery's ajax function.

Realistic solution

First, don't generate JS with PHP.

Then, make a function in the Session model to handle login. You can even avoid the Backbone REST function completely since it doesn't really fit the use-case for a login request.

Using a model is useful as it provides the usual Backbone events and it works well with plugins, like two-way bindings in a login form view. But calling save to login isn't clear what it's supposed to do. This is why we should provide a clear API for the Session model.

var Session = Backbone.Model.extend({
    urlRoot: "http://example.com/reddit/index.php/welcome/sessions",
    defaults: {
        username: null,
        password: null
    },

    // hide the login complexity inside a function
    login: function(options) {
        // for a really simple login, this would be enough
        return this.save(null, { type: 'POST' });

        // for anything more complex, make a custom call.
        return Backbone.ajax(_.extend({
            url: this.url(),
            method: "POST",
            data: this.attributes,
            dataType: "json",
        }, options));
    },

    // provide other functions for a clear and simple to use API.
    logout: function(){ /*...*/ },
    isAuthenticated: function(){ /*...*/ }
});

Then to login:

var session = new Session();

// in the view
render: function() {
    // caching jQuery object and uses the view's `$` function to scope
    // the search to the view element only.
    this.$username = this.$("input#username");
    this.$password = this.$("input#password");
    return this;
},
getdata: function(){
    session.set({
        username: this.$username.val(),
        password: this.$password.val(),
    });
    session.login({
        context: this,
        success: this.onLoginSuccess
    });
}

I personally use the backbone-session plugin to save the auth token in the localStorage. It provides a nice API out of the box and uses save and fetch to sync with the localStorage.

Why a custom ajax call?

Backbone offers save to sync the attributes with the server according to the REST principles, which adds a lot of overhead for a login service that doesn't need an ID or to make a PUT/PATCH request.

You'll often end up fighting against Backbone.

More information

Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
  • If we have a modal containing exactly the data we want for authentication, I'm not sure why the quick fix is a "quick fix". For me that'd be the practical solution. It's 1 line and it's backbon-ish. If there's no need of such model then we can directly hit jQuery Ajax. Maybe I'm missing something but Implementing a method that doesn't give any additional functionality seems a bit of overkill? – T J Jan 13 '17 at 14:33
  • @TJ For a simple one-time login call, I would probably just wrap the `save` inside the `login` function. But for anything more complex, I prefer a custom ajax call. Backbone offers `save` to sync the attributes with the server according to the REST principles, which adds a lot of overhead for a login _service_ that doesn't need an ID or to make a PUT/PATCH. You'll often end up fighting against Backbone. Using a model is still useful with the views and with its Backbone events. It also plays well with plugins. – Emile Bergeron Jan 13 '17 at 15:41