Backbone collections detach from models on reset/fetch - backbone.js

I am developing an application in which there are two views.
View 1 is a list of documents, presenting some vital details
View 2 is the document it's self. Editable.
The application is multi-user. So the app polls the server for updates to the collection.
The problem is that when collection (view 1) is refreshed (.fetch) it unbinds all events from the child models. Including the one open in view 2. Where as before the fetch, any changes in the document (model) were reflected in the list (collection), after the fetch the document (now old model) is now unrelated to the list (collection).
After looking at the backbone.js source, this is the intended behavior. Is there a work around solution to this?

Yes, this is a very common issue. The Collection is reseted and all its references refreshed, even if they target the same Models than before.
I think could be nice idea to implement a Collection.update() method in opposition of Collection.fetch().
Check this tread for approaches to deal with this behavior: Backbone.js collection upsert?

Related

Angular - Meteor subscribe/collection

I am new to Metoer and I have two dumb questions related to the meteor collection and the subscribe.
1) I understand that if I subscribed to a collection in one of my controllers, and it will load the data into my local collection and be persistent until I stop the subscription. my question is what if I have different views which need to access the same collection but the views are independent of each other which means, user can access any of the views without accessing the others first.
For example, if I have view to display all parties hosted by current user and all parties hosted by other users. What is the best way to subscribe it? I originally thought I can just subscribe in one controller to get all documents and do the filtering in the collection selector. But this won't work as user can access any of the views first. so I ended up subscribe to it in the two controllers. Is this the right thing to do?
$meteor.subscribe('parties').then(function(){
....
});
$scope.parties= $meteor.collection(function(){
return Parties.find({// select either my parties or others' parties});
});
2) My second question is that if I have a list view and a details view, I am trying to access the object in the details view's controller.
$scope.party = $meteor.object(Parties, $stateParams.partyId);
This works fine if I click the details button from the list view as the list view's controller has subscribed to all the documents.
However if user refresh the page from browser (which is not intended in a meteor app but we cannot stop users from doing that )? the object won't be accessible.
How can we deal with this in a Meteor app? I don't want to subscribe it again in details view even that will solve the problem.

Angular ui-router nested views don't refresh data retrieved by Angular Services

I have a nontrivial Angular SPA that uses ui-router to manage multiple views, many of which are visible at the same time. I need models to be visible across controllers, so I have services written that allow me to have controllers pull down fresh copies of model data that has been updated.
I apologize in advance for the length of the question, but I will state the problem then state what I have done to address issues I'm sure others in the Angular community have struggled with.
I believe my problem is not understanding the lifecycle of controllers / views, because I get behavior where a controller initializes correctly the first time I go there, but then seems to never run again, even when I navigate to it using something like $state.go("state name").
In one view (contrived example), I show a summary of information about a customer, and in another view I allow a user to update that customer's more detailed profile. I want a user to edit, say, the customer last name in the detailed view, and have the summary view automatically recognize the change and display it.
I have a fiddle that shows 3 views and a simple password changing Service. The flow goes like this:
You can see each view gets initialized and displays the initial password retrieved from the service. All views are in sync with the DataService.
The middle view allows you to enter a new password and change the one stored in the service. Console logging confirms that the service picks up the new password just like you would expect.
(odd behavior #1) When the DataService receives the new password, I would expect the other 2 views (top and bottom) to display the new one. They don't... they still display the initial password.
There is a button to allow a user to go to another state via $state.go("state name") (a child state of the original) which also retrieves the password and displays it. This works the first time (see #5). Now the top view shows the outdated password, the middle view shows the new one, and the bottom one shows the new one as well. This seems normal, since the new view is invoked after the DataService contains a new password value.
(odd behavior #2) If I click back in the middle view and change the password again, and click the button to change states again, the bottom view (which updated just fine in step #4) no longer updates its copy of the password. Now all 3 views show different passwords, even though I am using a single service to pass values between controllers as suggested pretty much everywhere you look for Angular best practices.
Some possible solutions:
Tim Kindberg has an excellent slideshow here that seems to recommend using ui-router's state heirarchy to "pass" data among views that need to pick up values from other views. For a smaller-scale app I think I would settle on this, but I expect our application to have 30+ views displaying data from over 100 REST endpoints. I don't feel comfortable maintaining an application where all the data is being shared by a complex inheiritance tree. Especially using a routing framework that is at version 0.2.8.
I can use events to have controllers listen for changes in the data model. This actually works well. To accommodate performance concerns, I am using $rootScope.emit() and a $scope.$onRootScope('event name') decorator I found on here. With this approach I am less concerned about event performance than I am about wiring this huge app with a bunch of event listeners tying everything together. There is a question about the wisdom of wiring a large app using angular events here.
Using $watch on the value in the DataService? I have not tried this but I am hesitant to hinge an app this size on hundreds of $watches for performances reasons.
A third-party library like bacon.js (or any of a dozen others) that may simplify the event spaghetti, or create observable models that my controllers can watch without the risk of $digestageddon. Of course, if there is a concise way to handle my issue using Angular, I'd prefer not to muddy the app with 3rd party dependencies.
Something that lets controllers actually reference .service modules by reference, so I don't have to depend on tons of event wiring, complex state hierarchies, 3rd party libraries, or seeding the app with hundreds of $watches and then kicking off $digests to update controllers' references to Angular services?
Some solution that relies on time-tested OO and design patterns and not a 3rd-party library or framework that has a version that starts with 0.*.
Thanks in advance... I appreciate the help!
This is no problem of ui.router. If you intend for your model (your data service) to be a single source of truth, you have to refrain from destroying it.. err.. the reference to it that is. And in your case, assigning a primitve (a string) directly to the scope, instead of a reference to it. In other words...
var password = {pw:'initial value'};
and then later setting/binding only on
password.pw = newpassword
{{password.pw}}
Heres a fiddle. And also here is a short little read on scopes, It also includes a video of an angular meetup where Misko talks about "always have(ing) a dot in your model" link and how the $scope is a place to expose your model, not be your model. (aka not a place to assign primitives like password = 'initial value')
Hope this helps!
try remove the animation property of your ion nav view.
remove the property
animation="slide-left-right"
it would be ok.

Can't listen to a event from one view to another view in Backbone.Marionette

I'm trying to port the code from existing backbone to backbone.Marionette application. Refer the following url for application that i have started.
http://www.adobe.com/devnet/html5/articles/backbone-cellar-pt1.html
According to my code structure,
I have 2 views in my code.
ItemView with a form
Composite View that contains list of itemViews for each li tags.
Initially on page load, it renders the data from db using fetch() call and appends all wine names to side bar. Then, on each wine name click, I can view its corresponding details.
My doubt is that, Everything works except listener from form itemView to CompositeView. I'll explain it in brief.
When i update/delete in the form ItemView, the particular li in CompositeView is not updated/deleted by listening to the event binder. It works if i use localstorage but not as server/db based app.
What should i do for listener to listen changes from form itemView and render it. Any suggestions would help me to continue furthur.
When using a Marionette CompositeView, the rerendering will be done for you. You do NOT need to add a listener to the model or collection, because Marionette automatically listens to those events.
If this doesn't solve your issue, put your code on jsfiddle so we have a functional example of the non-working code.
Edit based on jsFiddle :
I've added code that should make your example functional (hard to determine without a functional example) : http://jsfiddle.net/VvXDs/ Basically, I added an app-level message, and listen for it it the list to trigger render if necessary. Although this is functional, this pattern is bound to cause problems.
The main thing that is making your life more complicated, is the fact that you're managing the routing as if the application were stateless web app (more on that here http://lostechies.com/derickbailey/2011/08/03/stop-using-backbone-as-if-it-were-a-stateless-web-server/).
What's happening is that you have a collection with all of your chocolate, and a user clicks on a link to display one of them. Then, although you already have the data, you fetch a new instance of the model to display from the server. So obviously, the listener won't work: they're defined on 2 different instances (client side) of the same model (server side). (If you're worried about stale data, you should instead pass the same model instance to the view, and call fetch on that instance to update the data.)
A better design approach is to use the same client side model instance in both your menu and the form view. Then, when the model changes, the menu line item will automatically get updated (because they're using the same model instance, so the "change" event listener will word properly).
If you're interested in learning more about using routing in a stateful manner, take a look at the free sample to my book http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf (chapter "Implementing routing").
Remember: the code I added should work, but the design will probable make your development more challenging...

Why do backbone has sync method in models as well as collections?

Anyways using sync method only in collection or only in model can suffice, then why do they have to sync at both the places?
Actually both sync() methods are just proxies to a common Backbone.sync() method:
Model.sync()
Collection.sync()
Backbone.sync()
Collection always delegate in the Model.sync() for individual operations over its individual models like: create, remove and so on. But Collection uses its own sync() in the fetch() operation due it is very different to fetch a Model or a Collection, for example: the URL follows another patter and the backend layer should respond different.
In the other hand I see the Backbone.sync() as a private method and I try to not use it directly, if I'm doing this I don't feel well. I think the sync() method is a handler point to allow you to overwrite completely the backend synchronization a method that you can overwrite to implement different persistance layers as for example using LocalStorage. But not for be called directly.
As #JMM has said in the comments, the Model.sync() and Collection.sync() is also a good point to be overwrote to make it "does something custom and then calls Backbone.sync() to carry on as usual".
Backbone doesn't have a sync -method in models and collections by default, but both models and the collections have methods (fetch for both models and collections and save, destroy for models) that use the Backbone.sync -method to make ajax-calls. Docs, annotated source
The methods that use Backbone.sync check for the existence of a sync method for the individual collection or model, so the default functionality of sync can be overwritten for everything by overwriting the Backbone.sync or for specific parts by extending a model or collection that needs custom sync with a sync -function.
As to why both models and collections have the capability to synchronize with the server: flexibility. If only collections would have the syncing capability, then you couldn't have individual models, and if only models would have syncing capability, how would you fetch large batches of models initially from the server. There is no downside in having syncing capabilities for models and collections, so why not?
My counter-question for you: How would having sync on only the other suffice?

Backbone maintaining state

I am developing a JavaScript heavy single page app with Backbone.js. The goal is as follows;
The user starts with a set of multiselect boxes which are populated with filter elements to query a set of resources. These multiselect boxes are dependent of eachother. Furthermore, the elements in the multiselects are queried from the server and depend on the user that is logged in, in other words they depend on the resources that are associated with the user that is logged in.
The user fills out the multiselect boxes and presses a "filter" button. When this is pressed a collection is fetched, thereby using a set of query parameters (multiple array values) to get the set that reflects the filter elements.
When the collection is fetched the view with the resources appear. This view has multiple subviews, and it must be possible to drill down on specific resources while maintaining state (the collection that is fetched as a result of the query parameters)
How to maintain state in a Backbone app in such a use case? I've looked through many examples but all are to simple to be useful.
I am new to backbone.js and trying to develop a single-page app using Backbone.js. In my limited understanding of backbone.js documentation, I did not come across a better way of maintaining state using backbone.js core. However, in the past, I have worked with jStorage: http://www.jstorage.info/ , a simple wrapper plugin for Prototype, MooTools and jQuery to cache data (string, numbers, objects, even XML nodes) on browser side. It is simple to integrate and get started. In my app, I am going to use this for the time being... I thought this could be shared...hence I mention it here when I came across this question... I hope this would be of some help

Resources