I've run into a problem where calling destroy() on a model object triggers the "destroy" event but doesn't actually discard the model object.
I am using relations, but seem to be coming across the problem with or without relationships.
var stagelet = stage.stagelets().findByAttribute("reference", id);
stagelet.destroy();
Triggers the destroy event, but then calling:
stage.stagelets().all();
will still return the recently destroyed object. Are there situations in which these destroyed objects remain in the store or should I look elsewhere for my issue?
That looks like a bug, objects that are destroyed should not be returned by .all()
If you can submit a test case via a pull request on github we can look into it further.
Related
After reading the docs, this is my understanding of sync.
I instantiate some Backbone.Model and call Collection.create(). create() eventually calls sync() and the Model is POSTed to the server. Then there is a sync in the opposite direction such that the Model on the client is given an id.
Does this update then trigger componentDidUpdate()?
Note: componentDidUpdate is a ReactJS thing, so if that doesn't make sense, the question reduces to "Is the client-side model updated and the view re-rendered?"
Since inside of my componentDidUpdate() I am making a call to save() to keep everything up to date, this subsequently makes a call to sync() which then fires a PUT request (because the Model already has an id).
I'm asking, because in my current application, creating a TodoItem seems to result in a POST and then a PUT which I find redundant. Perhaps it is for an unrelated reason.
It actually fires two POSTS and then two PUTS when adding one item, but that is another question.
The first time you save a model (one which doesn't have an id) it will make a POST, thereafter it will make a PUT (update). I think you are confusing when to use create/add/save:
Use save at any point to save the current client collection/model state to the server
Use add to add Model(s) to a collection (a single Model, an array of Models, or an array of objects which contain attributes and let the collection create them)
Use create as a shorthand for creating a model, adding it to the collection, and syncing the collection to the server.
My guess is that you are calling create and save in one operation - you should be using add and save instead, or just create.
The view will not automatically update for you, you will need to listen to changes or events on the collection/model and update the view yourself - there is no equivalent of componentDidUpdate. For example:
initialize: function() {
this.listenTo(this.collection, 'sync', this.onCollectionSync);
},
onCollectionSync: function() {
this.render();
}
I recently started learning mithril.js and I'm wondering how can I make very basic Model -> View one way data binding app.
TestModel = function(data){
this.name = m.prop(data.name)
}
testModel = new TestModel({name: "John"})
code above declare a model and it works perfectly as getter/setter.
but how can I set an event listener for the model event like Backbone's listenTo('model',"change",callbackFunc)?
all sample codes I saw are setting events for actual user actions like click,keyup or onchange.but never listen to actual model value's state directly.
am I missing something or am I understanding how to use mithril.js wrongly?
thanks in advance.
One of the key ideas with Mithril is that changes usually happens after an event:
A user action like onclick or keyup defined in a m() view template
An ajax request made with m.request
Mithril automatically redraws after those, alleviating the need for most listeners.
If you are updating your models through some other method and you need to redraw manually, use m.redraw or m.startComputation / m.endComputation. Thanks to Mithril's DOM diff algorithm, redraws are very cheap so don't be afraid to use them (with some common sense, of course!) Check out the m.redraw documentation for more info.
It was always my understanding that .observes('someProperty') and .property('someProperty') worked exactly the same, except that the former is used for triggering function calls and the latter is used to keep object properties up to date.
But now I'm having a problem. My controller code looks like this:
_logChange: function(){
console.log('model array observer fired');
}.observes('model.#each'),
statsData: function(){
console.log('statsData being updated');
...
return someArray;
}.property('model.#each')
The observer and computed property both watch model.#each but for some reason, the observer fires on every model change and the property only updates TWICE before mysteriously going dead. statsData is calculated once on initial page load, and once on the first route transition, then after that, none of the transitions (with the changes in the underlying model they make) affect it.
What's going on here? Shouldn't they respond to change in the same way?
Note that I am using the statsData property in my template.
observers fire immediately, computed's fire as part of the run loop and scheduled in a debounced fashion. Currently all you're watching is that you add or remove an item to the collection, not whether or not a property on one of the items in the collection has changed. If you want to watch a particular property, you need to specify it.
statsData: function(){
console.log('statsData being updated');
...
return someArray;
}.property('model.#each.cost')
if you just want to watch the collection changing you should just use []
statsData: function(){
console.log('statsData being updated');
...
return someArray;
}.property('model.[]')
Thanks to the lovely folks on Ember IRC, I was able to figure it out. The problem was that I was passing statsData to a component, like this: {{common-statistics values=statsData}} and in the component, I had this function:
_validateValues: function(){
var values = this.get('values');
if(!values || !Ember.isArray(values) || values.length === 0)
{
this.set('values',[]);
}
}.on('willInsertElement')
which is, as you can see, setting values if it's not what the component is expecting. Unfortunately, this was affecting statsData on the controller as well, thanks to this JavaScript language feature. By setting statsData in the component, I was breaking the computed property on the controller.
So it was never a problem with Ember at all. I just failed to realize that object properties on Ember objects behave the same way they do on "regular JavaScript objects."
I work on a Backbone app, which utilizes a lot of view. I fell into the (usual I think) trap of instantiating a Router (sort of, the main controller) which is responsible for clearing out the views, instantiating new ones, and filling them with data. I say trap, because although JavaScript has a built-in garbage collector, one will quickly start noticing how the usability of the app gets hampered by the many unused views which still reside somewhere in memory.
I wish there were a way to recycle those views. I thought that this would be as easy as calling initialize() on the view with a new model, and then rerender. This is unfortunately not as easy.
Also, one would have to kinda "destroy" the view handles, for example, event handlers and stuff...
What would be a good practice to do this?
Once a view has been removed from the DOM it will be garbage collected. Unless of course you cache it. If you do cache a view and remove it from the DOM, all event handlers are garbage collected as well. Unless you use something like jQuery's detach method, which will preserve the event handlers.
http://api.jquery.com/detach/
If you want to recycle a view, simply cache it in a variable.
Inside your router's init method, do something like this:
this.views = {};
Then whenever a route is called check if the name of the view is available in the cache and if it is, use that, otherwise create a new one.
someRoute: function () {
var view;
if ( _.has(this.views, 'someRouteView') ) {
view = this.views.someRouteView;
} else {
view = new SomeRouteView;
this.views.someRouteView = view;
}
// You have a view now
}
Again, if you don't create a new view, you will have to use something like jQuery's detach method to preserve event handling.
The title of the question pretty much sums it up, I'd like my view to respond differently to a model instances initial save vs any future saves. Right now I'm grabbing the model's isNew attr before I save and then triggering a custom event, but I was wondering if there was anything built in?
Checking model.isNew() is the built-in way of telling whether the initial save has happened yet. If checking isNew is working for you, keep on doing it.
The initial save should issue an ID for the object, so you could bind a function to "change:id" and it would execute after the initial save succeeds. Or you could add logic to the "success" and "error" callbacks of create().
With help from this answer, I came up with the following solution:
var originalSync = Backbone.sync;
Backbone.sync = function(method, model, options) {
console.log(method);
originalSync.apply(Backbone, [method, model, options]);
};
I can now check what method is being called.