I'm playing with Ampersand JS models. When I'm trying to initialize a new one,
z.add(this.state)
m = z.get(this.state.name)
m.sync()
or add one to a collection,
m = new ZModel(this.state)
m.sync()
I get an error A "url" property or function must be specified
According to the spec:
By default, url is constructed by sniffing for the model's urlRoot or the model's collection url, if present, then appending the idAttribute if the model has not yet been saved.
This is exactly the behaviour that I want, since I have a restful API to sync with. urlRoot
is set, idAttribute
is set too.
export default Model.extend({
idAttribute: 'name',
urlRoot: 'http://localhost:50000/locator/zones/',
props: {
name: 'string',
type: 'string',
},
fetch () {
Model.prototype.fetch.apply(this, arguments)
}
})
A collection is defined, but I didn't pass it to the model, because I can't figure out from documentation how to do it. But supposedly it's not necessary as long as I have urlRoot
defined. What to do here? I guess I could pass the collection to the model, or define the url programmatically somehow?
Update:
If I do this:
m.save({}, {
success: function(model, response) {
console.log('Rerender now')
}.bind(this),
error: function() {
console.log('Error during model add')
}
})
I don't get the same problem anymore, but instead of getting a POST, I get 2 requests with OPTIONS and PUT. If I omit the empty object {} argument, behavior doesn't change. Even though the spec says this:
book.save();
//=> triggers a POST
via ampersand-sync with { "title": "The Rough Riders", "author": "Theodore Roosevelt" }
book.save({author: "Teddy"});
//=> triggers a PUT
via ampersand-sync with { "title": "The Rough Riders", "author": "Teddy" }
I guess the documentation omits a lot of details. What's the secret to getting this to work?
Thanks to rick-butler and aaronmccall from Ampersand gitter chat for the answer:
By default, if the model's ID attribute is populated the save method will PUT
. POST
vs PUT
/PATCH
is determined by whether the model has an ID by default. The actual logic is from the isNew()
function in ampersand-state
. You can overload this function to determine your own logic, or manually pass your preferred method in options.
In cases where I don't have a distinctive ID, I like to add an attribute called fetched
to the session of my derived ampersand-model
. When I fetch/retrieve the model from the server I set this value. I use that for my isNew
value, and I use it as the waitFor
attribute for subviews.
var Model = require('ampersand-model');
module.exports = Model.extend({
constructor: function(){
options || (options = {});
Model.apply(this, arguments);
this.onSync = this.onSync.bind(this);
this.on('sync', this.onSync);
},
isNew: function(){
return this.fetched;
},
session:{
fetched: ['boolean', true, false],
},
onSync: function (model, resp, options) {
if (options.xhr.method == "GET") {
this.fetched = true;
}
}
});