emberjs / data Goto Github PK
View Code? Open in Web Editor NEWA lightweight reactive data library for web applications. Designed over composable primitives.
Home Page: https://api.emberjs.com/ember-data/release
License: Other
A lightweight reactive data library for web applications. Designed over composable primitives.
Home Page: https://api.emberjs.com/ember-data/release
License: Other
The actual situation do not feel totally right.
A few suggestions :
on the adapter we could have createModel
, updateModel
and deleteModel
for consistency
on the store createModel
and removeModel
(as it take model as argument it is different from models deleteModel)
on the model maybe we could reuse destroy
by overriding it and doing something like this :
if (this.isDestroyed) {
this._super();
} else {
do wat we have to do
}
There is another delete
in state manager but it is private so I do not really care about naming :)
Any thoughts?
E.g.:
{
name: {
first: 'Devin',
last: 'Torres'
}
}
Thoughts:
name: DS.attr('object')
firstName: DS.attr('string', { key: 'name.first' })
Justification:
Nested JSON objects are too prevalent to require transforming them every time they're used. Models should model the data, not some transformed representation you morph in adapter, and hopefully not through hundreds of transformers.
Hi, i'm trying to update a record in this way:
if value
project = Lazier.selectedProjectController.content
project.set('name')
Lazier.store.commit() # updateRecord?
Here's the full code: source
The update works in Rails (I'm having a "WARNING: Can't mass-assign protected attributes: id" message, i don't know if this is the problem), but, I'm getting the next JavaScript error:
Maximum call stack size exceeded
meta
w_get
get
DS.Model.Ember.Object.extend.unknownProperty
Ember.wrap.newFunc
w_get
get
DS.Model.Ember.Object.extend.unknownProperty
Ember.wrap.newFunc
What is the best way to update a record?
Thanks :)
Currently (as of 1/22/2012) many of the examples in the README.md for ember-data use this pattern:
var url = type.url;
url = url.fmt(id);
However this causes an error since type.url is not defined, as far as I can tell, in either the current trunk of ember.js or the current trunk version of ember-data.js. Perhaps it's a holdover from Sproutcore. In any case, I hope this can be fixed quickly so that the README examples work. Thanks!
Currently, DS.Adapter#findQuery
has to give the modelArray.load
an array of hashes of all the returned data.
In addition, it should be possible to tell the modelArray or the store only the ids of the records returned.
Then, the modelArray would lazy load the actual model instances upon DS.ModelArray#objectAtContent
.
This was possible in SC.DataSource by only returning storeKeys back to the store.
I have a DS.Adapter#findQuery call that returns records of multiple types from the server's response, which I want to load into its modelArray. This is important because the server returns them in a specific order which I want to preserve when rendering them via {{#each}} in one of my templates.
However, the modelArray that is passed to DS.Adapter#findQuery is of type DS.AdapterPopulatedModelArray, which only supports one type of model per modelArray. Furthermore, the DS.Store#find which I use to invoke the query in the first place takes as its first argument a type.
A workaround is to use one DS.Model subclass and fake the types in some other way.
Hi,
Is it possible to unload a model from the store ?
Multiple users can be connected to my application. If one of them delete a model (record), the server send a message to the other clients to update. Those users need to remove the model without deleting it, the record has been already deleted. How can I do that ?
An other use case: a user can perform a search on the server using a Query. I want to flush (unload) the search result (model array) once the search is over.
Thanks.
Jeff
App.store.create App.person
name: "John"
App.store.commit()
# Adapter saves data to server. Server returns newly created object that includes the id field. Adapter calls the didCreateModel method on the store.
{{#view App.PersonView contentBinding="this"}}
{{#with content}}
{{id}}
{{/with}}
{{/view}}
The above view never updates with the correct id returned from the server.
SC.Store had a #commitRecordsAutomatically property, which was very useful for simple apps.
When any model instance changes, it appears to call store#hashWasUpdated, which could then call commit if commitAutomatically was true.
Currently the documentation for findAll doesn't specify whether or not the ModelArray it returns will automatically update with newly created instances of that Model type.
Instead, the documentation should clarify one way or the other.
It's confusing and instead we should have DS.attr properties explicitly specified.
With #85 we should have something equivalent to specify attributes without a type and just pass through whatever values as is both ways.
Perhaps DS.attr('identity')
or just DS.attr()
?
When calling a ModelArray instance's filter method, it should return a FilteredModelArray with the results. When the contents of the model array update, either by new model instances entering/leaving the model array or the contents of those models changing, the filtered model array should be updated accordingly.
I have the following models:
App.Section = DS.Model.extend({ title: DS.attr('string'), }); App.Document = DS.Model.extend({ name: DS.attr('string'), sections: DS.hasMany(App.Section), });
now I preload the documents (for App.Document.sections
I set an array of section ids) and for example-purpose one of them is myActiveDocument
now I want to load the sections, but how?
if Ido App.store.findMany(App.Section, myActiveDocument.get('sections')))
it does not work. By experimentation I found out that findMany
expect as second argument an array of ids, then it halfway works:
var arr = myActiveDocument.get('sections').map(function(item, index, self){ return item.get('id') }); App.store.findMany(App.Section, arr));
Now I bind my data to a view and realize that the first time I call App.store.findMany(App.Section, arr));
the view gets populated with empty elements, the second time I call it, it gets populated with the proper elements.
So I guess there is anything wrong with findMany
or missing documentation on how to use it properly (and yes I have implemented the adapter and serverside for it and that part seems to be fine)
In the readme you write
NOTE: The default RESTful adapter is in progress. For Rails applications, it will work seamlessly with the
active_model_serializers gem's conventions. In the meantime, see the section on rolling your own adapter.
Does this mean it currently does not work at all?
At least if I do
app.store = DS.Store.create({
adapter: 'DS.RESTAdapter'
});
or just app.store = DS.Store.create();
then I see no actions at all. Just for confirmation as the restadapter code does not seem worse than the readme code to me...
I have a very simple computed property that depends on a hasMany
relationship. I can compute the property just fine by itself. However, when I have a two-way binding to that property, I see an infinite loop. Ember continually tries to get and set the same property.
Note that the infinite loop occurs only when all three things overlap (a two-way binding, a computed property, and a hasMany
relationship). If any one of these does not occur, then there is no problem. To be explicit, I do not see a problem:
hasMany
relationship itself, instead of a binding to a computed property of the hasMany
relationship;hasMany
relationship; orI have spent some time getting a minimal example demonstrating the problem, which I've included below.
window.App = Ember.Application.create({
Store: DS.Store.create()
});
App.Number = DS.Model.extend({ primaryKey: 'value' });
App.Set = DS.Model.extend({
numbers: DS.hasMany('App.Number'),
allNumbers: function(key, value) {
if (arguments.length === 1) {
return this.get('numbers').mapProperty('value');
// This also causes an infinite loop:
//return [1,2];
}
}.property('numbers'),
});
App.Store.loadMany(App.Number, [
{ 'value': 1 },
{ 'value': 2 }
]);
App.Store.loadMany(App.Set, [
{ 'id': 1, 'numbers': [1, 2] }
]);
App.ViewingSet = null;
App.Object = Ember.Object.create({
// This works if you replace 'from' with 'oneWay'.
aBinding: Ember.Binding.from('App.ViewingSet.allNumbers')
});
var start = function() {
App.set('ViewingSet', App.Store.find(App.Set, 1));
};
Ember.LOG_BINDINGS = true;
Here is the HTML I used. ember.js
is the latest code from the master branch of ember (commit 1ce7eb6e3a) and ember.data.js
is the latest code from the master branch of this repository (commit 660cb75).
<html><body>
<h1>Looping bug</h1>
<a href="#" onclick="start()">click me to loop forever</a>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.js"></script>
<script src="ember.js"></script>
<script src="ember.data.js"></script>
<script src="app.js"></script>
</body></html>
To illustrate the problem, you'll need to save the following HTML and open it up locally in a browser: https://gist.github.com/1532069
In the console, create a couple new models
var ember = App.store.create(App.Venue, {name: "Ember"});
var wycats = App.store.create(App.Venue, {name: "wycats"});
Click on "Ember".
Notice that "wycats" changed to the same value as "Ember". Is this somehow related to #11?
What's weird is the views don't update if I try to update the instance that got returned by create
in the console:
ember.set("name", "tomdale"); // doesn't update the DOM
But this works
App.venues.objectAt(0).set("name", "tilde");
Our usecase is we are putting together data in our API from multiple sources and packaging to send to the UI.
We are using partly relational data from our DB (with id's) partly data from config documents and partly data gleaned from reflecting methods from plugins in our application (without id's).
This scenario could be considered to be very similar to data coming from a document store such as mongo or couch, and a solution would probably fix those cases also.
The following is a small example data structure extracted from a much larger structure. Hopefully it demonstrates most issues:
{
"group": {
"id": "099bfb6c-71c0-4b6d-99bc-0d475df37e30",
"name": "Group 1",
"rules": [
{
"target": "ObjectType",
"name": "Rule Name",
"appliesOn": ["Monday", "Tuesday",
"Wednesday", "Thursday",
"NotNationalHoliday"],
"parameters": {
"startTime": 570,
"endTime": 960,
"requireRemarks": false
}
}
]
}
}
In order to handle this example we need attribute arrays (#96), dictionaries where value type is not pre-defined (#71 or similar), and nested models that only exist in the context of their parent (ie, they don't have their own id). Also when we commit changes to this structure we need to POST the whole structure, not just the sub-model-element that changed.
Of course we could break this structure down into a pseudo-relational representation, but things start getting large and ugly:
{
"group": {
"id": "099bfb6c-71c0-4b6d-99bc-0d475df37e30",
"name": "Group 1",
"rules": [
{
"id": "099bfb6c-71c0-4b6d-99bc-0d475df37e30_rule1",
"target": "ObjectType",
"name": "Rule Name",
"appliesOn": [
{
"id": 1,
"name": "Monday"
},
{
"id": 2,
"name": "Tuesday"
},
{
"id": 3,
"name": "Wednesday"
},
{
"id": 4,
"name": "Thursday"
},
{
"id": 8,
"name": "NotNationalHoliday"
}
],
"parameters": [
{
"id": "099bfb6c-71c0-4b6d-99bc-0d475df37e30_rule1_param1"
"name": "startTime",
"value": "570"
},
{
"id": "099bfb6c-71c0-4b6d-99bc-0d475df37e30_rule1_param2"
"name": "endTime",
"value": "960"
},
{
"id": "099bfb6c-71c0-4b6d-99bc-0d475df37e30_rule1_param3"
"name": "strequireRemarksartTime",
"value": "false"
}
]
}
]
}
}
This structure would probably load, but changes could be difficult to manage, since some sub-elements do not have meaning outside of their context, so we really need to POST back the whole document.
DS.SubModel
that can only exist in the context of a DS.Model
, changes to a DS.SubModel
would cause the parent DS.Model
to be commited (including all sub models).If I have an observer like this:
isDirtyDidChange: function() { // Workaround https://github.com/emberjs/data/issues/72
if (this.get('isDirty') && !this.get('isSaving')) {
this.get('store').commit();
this.get('store').commit();
this.get('store').commit();
this.get('store').commit();
this.get('store').commit();
}
}.observes('isDirty'),
the underlying adapter's commitRecord should only be called once; not 5 times
I build ember-js via bundle install
and rake dist
and included it in my ember 0.9.3 application, but I'm getting this error:
ReferenceError: Can't find variable: DS on line 3.
It looks like something with the bpm-built closure-exports-wrapper is wrong.
I'm looking into writing an adapter for IndexedDB. One of the technical hurdles is that IndexedDb has a setup process wherein the local database is mirated and indexed. I wanted to know if you guys had any opinions or ideas on how data-core could accommodate database configuration and migration. I figure migration would need to receive the complete set of models so it could query their structures, create the appropriate indices, etc.
I've got some code that is trying to call modelArray.replace(0, 0, [newModel]) which is just inserting the model instance directly into the modelArray's content.
Instead, somehow the newModel's clientId should be inserted into the modelArray's content instead.
Do you intend to provide float
at some point (and do some parseInt
/ parseFloat
magic in transforms)?
There seem to be a problem with associations and Ember.Select (built-in view). My guess is that the objects are compared with === and the comparison returns false, since they are different instances. I've tried to track down the lines in the source where this happens, but haven't found it.
Handlebars code:
<script type="text/x-handlebars">
{{#view EmberApp.MyView }}
<p>Neither of these selection bindings work:</p>
{{view Ember.Select
contentBinding="EmberApp.AllCountries"
selectionBinding="user.country"
optionLabelPath="content.name"
optionValuePath="content.id"}}
{{view Ember.Select
contentBinding="EmberApp.AllCountries"
selectionBinding="user.countryId"
optionLabelPath="content.name"
optionValuePath="content.id"}}
{{view Ember.Select
contentBinding="EmberApp.AllCountries"
selectionBinding="testId"
optionLabelPath="content.name"
optionValuePath="content.id"}}
{{/view}}
</script>
This is the javascript:
window.EmberApp = Em.Application.create()
EmberApp.store = DS.Store.create({
adapter: DS.fixtureAdapter
})
EmberApp.Country = DS.Model.extend({
name: DS.attr('string')
})
EmberApp.Country.FIXTURES = [{ id:"us", name: "US"}, { id:"se", name:"Sweden"}];
EmberApp.AllCountries = Ember.ArrayProxy.create({content:EmberApp.Country.FIXTURES});
EmberApp.User = DS.Model.extend({
country: DS.hasOne(EmberApp.Country, { key: "countryId" })
})
EmberApp.MyView = Em.View.extend({
user: EmberApp.store.createRecord(EmberApp.User, {
name: "Kalle",
countryId: "se"
})
testId: "se" #
})
console.log( EmberApp.store.find(EmberApp.Country, 'se') )
Currently there appear to be four attribute transforms: boolean, date, integer (which is actually number) and string. In addition, I'd like the ability to define DS.attr('object').
I have JSON like the following:
{
class: 'Car',
id: 1,
info: {
make: 'Nissan',
model: 'Altima'
}
}
I'd like to do something like the following:
App.Car = DS.Model.extend({
info: DS.attr('object')
});
var car = App.store.find(App.Car, 1);
var make = car.get('info').make;
For large fetches, is more adequate to retrieve records in a batch of 50/100/X, instead of retrieving all, we need to make to fetch in one call, retrieve the total count of records and the first range of records to be fetched to the array.
Do we need models, stores, adapters etc just to communicate with a server? It seems flexible but over engineered.
All this jazz was one of the reason original SC was hard to use imo. I know there are other libraries and ways to do it but it would be cool if the default way of embracing how things should work was as simple as possible.
http://jsfiddle.net/pixelcort/TZbw3/
I'm creating a new instance of a model and trying to set one of its hasOne attrs to a loaded model from the server.
However, it doesn't seem to actually be setting.
This line will allways fail when the model id === 0
since !!hash[primaryKey]
for 0
will be false
.... Should an item with an id === 0
be valid?
ember_assert("A data hash was loaded for a model of type " + type.toString() + " but no primary key '" + primaryKey + "' was provided.", !!hash[primaryKey]);
The README.md mentions to use rackup
, which doesn't work.
Using bundle exec rackup
does, however work. The main ember.js readme properly documents this.
I have data from the server like:
{
"id": 1,
"name": "Bob",
"tags": [
{
"id": 10,
"name": "Happy",
"color": "Green"
},
{
"id": 11,
"name": "Sleepy",
"color": "Blue"
}
]
}
I'd like to do something like the following:
App.Tags = DS.Model.extend({
primaryKey: 'id'
});
App.People = DS.Model.extend({
primaryKey: 'id',
name: DS.attr('string'),
tags: DS.childrenAttr(App.Tags)
});
and then when I do var happy = person.get('tags').get('firstObject')
I'd like to be able to call happy.set('color','Yellow')
which would cause person.data.tags[0].color === 'Yellow'
.
Reading the code, I just stumbled upon OrderedSet which is defined in store.js AND in transaction.js with the same implementation.
Is this supposed to be like that? Maybe not, one instance could be removed...
When we create a new record, or mostly when we will update a record, and the users updates some fields, and then decides to cancel editing this record, we need to go back to the previous hash, with nested store we can create a tmp store with these edited hash, if the user commits and is successfully updated, the new hash will be merged with the main store, if update is failed or users cancel we revert back by canceling/ignoring the new hash.
Was looking for a way to fetch a model when you don't yet know the id. For example /people/current-user
instead of /people/99', or to fetch items that don't have an id such as
/session-info`.
store.findMany
will return an array, but I want to get a single model object that can I can pass to a view.
Tried `/people/0' that returns a person with the real id, but then the system won't match up because then id's don't match.
Perhaps it might possible to create an item with a clientId
then match that up with the ajax response and wrap it up in a store.findOne
method?
since there might be many attributes for a given model, i think it would be a good idea to remove as much boilerplate code when creating an attribute,
how about the following interface:
App.Person = DS.Model.extend({
attributes: [
{'firstName': 'string'}
,{'lastName': 'string'}
,{'fullName': function() { return this.get('firstName') + ' ' + this.get('lastName')}.property('firstName', 'lastName')}
]
});
i think this will also allow for a cool syntext in coffeescript something like this:
App.Person extends DS.Model
attributes:
firstName: 'string'
lastName: 'string'
fullName: (-> return "#{@get('firstName')} #{@get('lastName')}").property('firstName','lastName')
After loading remote data with store.findAll() sometimes the #each template updates with incorrect data, showing the data of the first item in all of the items, even id the controller holds correct data.
<script type="text/x-handlebars">
{{#each App.records}}
<p>{{name}}</p>
{{/each}}
</script>
App = Ember.Application.create({
records: []
});
App.serverAdapter = DS.Adapter.create({
findAll: function(store, type) {
var url;
if (type == App.Publication) {
url = "publications.json";
} else {
url = "posts.json";
}
$.ajax({
url: url,
success: function(data){
// returns from server
// [{"id":1, "name":"Pub one"},{"id":2, "name":"Pub two"}] // for "publications.json"
// [{"id":1, "name":"My first post"},{"id":2, "name":"My second post"}]// for "posts.json"
store.loadMany(type, data);
}
});
}
});
App.store = DS.Store.create({
adapter: App.serverAdapter
});
App.Publication = DS.Model.extend({
name: DS.attr('string')
});
App.Post = DS.Model.extend({
name: DS.attr('string')
});
App.store.findAll(App.Post)
App.set('records', App.store.findAll(App.Publication));
Sometimes, I repeat sometimes, the output is:
<p>Pub one</p><p>Pub one</p> when it should be <p>Pub one</p><p>Pub two</p>
Here is a jsfiddle that illustrate the issue:
I would expect:
First New Name .
Second New Name .
It is common practice to send DELETE commands to a server, and later somehow the thing that was deleted is magically undeleted server-side.
When the undeleted thing is loaded back into the store, somehow its state should move out of the deleted state and back into the loaded state.
I've got places where when I call DS.Store.#filter
I'd like to also fetch some data from the server one time to populate the store and in turn possibly populate the result the filter.
I don't want to use DS.Store#find
with a query because the server could be sending back additional instances of the given type that I'm trying to filter out.
It is common convention to have ember properties like firstName and lastName, however it is common convention for most APIs to use first_name and last_name in their JSON keys.
When defining a DS.attr, if no key is specified, the default should change from the property name to converting things like 'firstName' into 'first_name'.
I'm in the middle of implementing my own adapter and am struck by the inability of the adapter to signal failure to complete the given operation. Reading the source I was able to find recordWasInvalid(), to which it appears I can pass in the results of a validation failure, however there are a bunch of failure modes I can think of off the top of my head which are not catered for: timeout (or generic transport error), not found, permission denied, etc. Probably the nicest solution would be to use the HTTP status codes and place error callbacks on model objects.
In my adapter my server sometimes sends me updates to already loaded models.
When I send them to store.load, it in turn sends the data to the model instances.
However, if the model is already loaded, it doesn't support loading updated data.
var App = Em.Application.create();
App.Person = DS.Model.extend();
App.Person.reopenClass({
url: '/people?ids=%@'
});
App.serverAdapter = DS.Adapter.create({
find: function(store, type, id) {
var url = type.get('url');
url = url.fmt(id);
$.getJSON(url, function(data) {
store.load(type, id, data);
});
}
});
App.store = DS.Store.create({
adapter: App.serverAdapter
});
App.store.find(App.Person, 1);
I wanted to give Ember.js-Data a try, but after executing the code above in Google Chrome console (with jQuery, Ember.js and Ember.js-Data included), this error message appears in console log: TypeError: Object App.Person has no method 'get'
I'm not sure If I am doing something wrong, but I used code snippets from the README.md file.
I have an App.MyModel = DS.Model.extend({myProperty: DS.attr('string',{key:'my_property'})});
I then do an App.store.findAll(MyModel)
and later a var myModelInstance = allMyModels.get('firstObject')
.
When I go to myModelInstance.set('myProperty','blah')
and then when I call myModelInstance.get('myProperty')
it's the old value from the data hash (from the server). I was expecting the new value I just set.
i think this should be at least an option for a smooth integration with the Ember project.
Here's the scenario:
You load a list of records with findQuery but the server only returns a few fields for each record. Afterwards, when the user navigates to a "detail" screen, you need to fetch the rest of the fields for the record from the server so you call App.store.find(type, id) and the store returns the already fetched record, there's no way to tell the store to fetch ask the adapter for the record again.
Also, any suggestions for a work around are appreciated.
I am not seeing a good way to create model classes that have default values for their attributes. I run into various issues deep in the stack when I set the data
property directly or inside init
. What would be the best way to implement this?
SproutCore included an SC.NestedStore system where instances of records could have buffered changes in a nested store.
Ember Data should include a similar NestedStore.
Currently DS.Store#findAll
returns an instance of DS.ModelArray
, which does not include an isLoaded
property.
Instead, DS.Store#findAll
should return something that includes an isLoaded
property.
When the adapter returns all the data for the findAll
, the isLoaded
property on the originally returned result of DS.Store#findAll
should change to true
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.