Skip to content
This repository has been archived by the owner on Apr 11, 2023. It is now read-only.

Dualstorage Model without Collections #98

Open
damanic opened this issue Mar 20, 2014 · 17 comments
Open

Dualstorage Model without Collections #98

damanic opened this issue Mar 20, 2014 · 17 comments
Assignees

Comments

@damanic
Copy link

damanic commented Mar 20, 2014

I'm fresh baby bum new to backbone.js so go easy.

I have a customer profile model that I want to use dualstorage on, there is no need for a collection. It appears to me that dual storage does not work unless called through a collection. Is this correct?

As set up below, when loading a view model.fetch() does not call an ajax request with dualstorage enabled. With dual storage removed the data is called in fine.

return Backbone.View.extend({

    initialize: function () {
        this.model.fetch();
        this.model.bind('change', this.render, this);
    },

    render: function () {
        this.$el.html(template(this.model.toJSON()));
        return this;
    }
});

Do I have to set up a collection or?

@nilbus
Copy link
Owner

nilbus commented Mar 21, 2014

That's strange; it should work on a model that's not in a collection. I
assume you made no change to your model for dualstorage? Does your model
have a url or urlRoot property?

@damanic
Copy link
Author

damanic commented Mar 21, 2014

The model I am experimenting with:

define(function (require) {

    "use strict";

    var $                   = require('jquery'),
        Backbone            = require('backbone'),
        dualStorage         = require('dualStorage'),

        Customer = Backbone.Model.extend({

            defaults:{
                id: '',
                first_name: '',
                last_name: '',
                email: '',
                company: '',
                phone: ''
            },
            urlRoot: "http://mysite/api_v1/session/customer/",


            initialize: function (attributes,options) {

                //set a error handler to catch not authorised 401's
                //http://stackoverflow.com/questions/6150514/global-error-handler-for-backbone-js-ajax-requests
                options || (options = {});
                this.bind("error", this.defaultErrorHandler);
                this.init && this.init(attributes, options);



                // Hook into ajax prefilter
                //send access token as header if available
                var that = this;
                $.ajaxPrefilter( function( options, originalOptions, jqXHR ) {

                    if (!options.crossDomain) {
                        options.crossDomain = true;
                    }

                    //use local access token if available
                    var access_token = localStorage.getItem("X-Lemonstand-Api-Token");
                    if(access_token){
                        jqXHR.setRequestHeader('X-Lemonstand-Api-Token', access_token);
                    }

                });

            },
            defaultErrorHandler: function(model, error) {
                if (error.status == 401 || error.status == 403) {
                    Backbone.history.navigate('#login', true);
                }
            },
            login: function(creds) {
                this.save({username: $('#username').val(), password: $('#password').val()}, {
                    success: function (response) {
                        var data = response.toJSON();
                        localStorage.setItem("X-Lemonstand-Api-Token",data.access_token);
                        Backbone.history.navigate('#', true);
                    }
                });
            },
            logout: function() {
                // Do a DELETE  clear the clientside data

                var that = this;
                this.destroy({
                    success: function (model, resp) {

                        //clear model
                        model.clear();
                        //delete local stored token
                        localStorage.removeItem('X-Lemonstand-Api-Token');
                        //send to login screen
                        Backbone.history.navigate('#login', true);



                    }
                });
            }


        });

    return new Customer();


});

@nilbus
Copy link
Owner

nilbus commented Mar 21, 2014

I included the model from your example code on the SpecRunner.html page, and calling fetch did indeed call through to the (mock) Backbone.sync.

How did you determine that ajax calls are not happening when dualsync is installed? Are you looking at the chrome inspector network requests?

@damanic
Copy link
Author

damanic commented Mar 24, 2014

Sorry for delay, I'm juggling some other projects at the moment. When I get back onto this one I will look at it again and get you more information.

I was looking at chrome yes, there were no network requests with dual storage on, but fine when off.

@elad
Copy link
Contributor

elad commented May 11, 2014

Hello,

I believe there's a bug here, because when I try to fetch a model that is not attached to a collection and doesn't have an id I get an exception because Store.find returns null and then my own parse function tries to access it. (This isn't a problem with a collection, because then Store.findAll simply reads the ids from localStorage and sets them appropriately.) When I explicitly set the id field (or whatever idAttribute says) everything works fine.

Can someone confirm this behavior and chime in on whether it's intended or not? My gut feeling says that it's not, because embedding the id in the code is not a robust solution...

If this is indeed a problem, I would suggest the following in Store.find, right after entry:

if (!model.id && !model.collection && this.records.length === 1) {
  model.set(model.idAttribute, this.records[0], { silent: true });
}

Or in CoffeeScript:

if not model.id and not model.collection and @records.length is 1
  model.set model.idAttribute, @records[0], silent: true

This fixes the problem for me at least.

Thoughts?

@elad
Copy link
Contributor

elad commented May 11, 2014

Also, to really make this work we need an equivalent of dirtyModels, destroyedModelIds, and syncDirtyAndDestroyed for models.

Since we're talking about a single model, it can only be clean, dirty, or destroyed, and we always know its id, so maybe the API should be:

  • isDirtyOrDestroyed returns 'dirty', 'destroyed', or null
  • syncDirtyOrDestroyed checks for what is required and either calls save or destroy

If this makes sense, then perhaps it's also wise to rework the API in general to have more consistent naming - but we can discuss that elsewhere.

@elad
Copy link
Contributor

elad commented Oct 6, 2014

Hey @nilbus, what's the status on this and other (async, IndexedDB) changes?

If you're still interested, I could submit new pull requests with tests for some of the issues.

@nilbus
Copy link
Owner

nilbus commented Oct 6, 2014

Unfortunately I'm having to take a hiatus on this project until early 2015
because of something more urgent that came up that is taking my free time.

Last I recall, I was trying to detemine if an issue I found in the async
branch when rewriting the tests was legitimate or not. I didn't come to any
conclusion before I stopped.

Sorry I can't be more help right now.

@elad
Copy link
Contributor

elad commented Nov 2, 2014

Hi again @nilbus, I'd like to help more with this project, even as a contributor if you're interested. (I'm biased: I use it in a real-world environment. ;)

What's on your todo list? There was the async branch, the tests rewrite using proper Backbone models/collections and Mocha, and the multiple backend support. If you point me in the right direction in terms of priorities and problems you've encountered I'll look into things. I think it would be unfortunate to let dualStorage freeze for a few months...

@nilbus
Copy link
Owner

nilbus commented Nov 10, 2014

@elad Thank you, and please excuse the delay. I'll let you know shortly what I had been working on.

@SonoIo
Copy link

SonoIo commented Nov 10, 2014

Hi @nilbus, probably you remember me. I'm working on a similar project inspired by DualStorage called BackboneIDBDualStorage that is an exactly porting of DualStorage to IndexedDB. I'm happy to share my experience with @elad and you, if possible. I've touched the limits of the current architecture and I can help with the v2.0.

@nilbus
Copy link
Owner

nilbus commented Nov 10, 2014

Hi @SonoIo , let's continue this discussion in #73

@nilbus nilbus modified the milestone: 2.0 May 3, 2015
@jmeit
Copy link

jmeit commented Jan 20, 2017

Would really love to see syncDirtyOrDestroyed() for models without collections.
Everything @elad suggested in this comment, from above, is bang on.

@nilbus
Copy link
Owner

nilbus commented Jan 20, 2017 via email

@nilbus
Copy link
Owner

nilbus commented Jan 20, 2017

what's the status

@elad To answer your earlier question from forever ago, the async/indexedDB branch got pretty hard to read with the async implementation. I started questioning whether it was worth it to make that change, given that there are other similar async indexedDB libraries out there already. That's where I left off.

Do you still use this in production? I'm not very active here recently, and the project could indeed use a new maintainer that actually uses the library. I do not.

@elad
Copy link
Contributor

elad commented Jan 22, 2017

@nilbus unfortunately, no, I no longer use Backbone in production. :/

@nilbus
Copy link
Owner

nilbus commented Jan 23, 2017 via email

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants