简体   繁体   中英

Backbone.js (with Require.js) variable/scope access issue

I'm trying to figure out how best to resolve an architectural issue with Backbone.js/Require.js

I have a test project here: https://github.com/Integralist/Backbone-Playground

The problem I'm having is that I'm creating a View in my main script file and then in another View script file I'm trying to access the other View but I don't know how to do it other than setting a global variable/property?

https://github.com/Integralist/Backbone-Playground/blob/master/Assets/Scripts/App/main.js#L73 is where I'm setting the global and https://github.com/Integralist/Backbone-Playground/blob/master/Assets/Scripts/Views/Contacts.js#L34-35 is where I'm accessing it.

I can't seem to wrap my head around how else to access it.

I know that this is just one global being set and if I had to keep it like that then I could also limit any damage by namespacing the global like so: window.myapp.contact_view = new ContactView(...) but this feels like an ugly workaround for this type of scope issue.

Any advice greatly appreciated.

UPDATE: Addy Osmani from Google has since tweeted me to suggest that namespacing my global is the best thing I can do in this instance, but I'll leave this question open for a while to see if there are any other suggestions that crop up.

The guru has spoken :) (Addy Osmani)

Here's what you can/should do IMHO - wrap your code in a self-executing function block:

File1.js:

(function(myNameSpace){
 // do something
 myNameSpace.sharedValue = something();

})(window.myNameSpace = window.myNameSpace || {});

Repeat the exact same code (structure) in File2.js

The last line makes sure that whichever file is loaded first the object is created and the same object is then used across files. Passing that same argument to the function allows you to access myNameSpace object in the function itself.

Other files can extend/augment/use the object as they deem fit. Basically there is no way to share variables in javascript (across files) other than exposing globals but can be done in a nice way :)

Try this for ContactsView.js:

define([ 'backbone' ], 
function(B) {

  return B.View.extend({

    display_selected: function(event) {
      this.options.contactView.render(model);
    }

  })

})

In your code,

new ContactsView({
  contactView: new ContactView( ... ) 
})

Anyway, you should probably create your injected view from ContactsView and just pass the required information as extra option values.

I've decided my best option is to use the global namespace as suggested by Addy Osmani, BUT I think if I needed an alternative option then I would just set an instance specific property like so:

contacts_view.contact = new ContactView({
    el: $('#view-contact')
});

I can then access the View's render() method from within contacts_view like so...

var ContactsView = Backbone.View.extend({
    events: {
        'change select': 'display_selected'
    },

    display_selected: function (event) {
        this.contact.render(model);
    }
});

...this feels cleaner than the single global namespace option but I'm worried that this alternative solution could get messy if I ended up needing to tie more than one View to ContactsView . I don't know why I would need to tie in more than one View but it's still a potential mess waiting to happen, so I think having a single global namespace is the best option (for now).

UPDATE: I've realised I can pass in additional data when creating a View instance and so that's what I've done here...

var contacts_view = new ContactsView({
    el: $('#view-contacts'),
    collection: contacts,
    associated_view: new ContactView({
        el: $('#view-contact'),
        collection: contacts
    })
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM