Ember App Kit with ember data - ember.js

I'm trying to start a new project with ember app kit and ember data using ES6. I've managed to create a store using the following code in adapter.js
var ApplicationAdapter = DS.FixtureAdapter.extend();
export default ApplicationAdapter;
However, I'm failing to create a model and access it. In models/account.js I have this
var Account = DS.Model.extend({
name: DS.attr('string')
});
Account.FIXTURES = [
{
'id': 1,
'name': 'Acc 1'
}, {
'id': 2,
'name': 'Acc 2'
}
]
export default Account;
and in my routes/accounts.js I have this:
var AccountsRoute = Ember.Route.extend({
model: function() {
var store = this.get('store');
return store.find('account');
}
});
export default AccountsRoute;
At this stage I'm simply trying to get a list of accounts from the fixtures displayed on screen. The route works nicely and if I put in static data (like the index route) then all works fine. However, with the code above, I run into trouble
DEPRECATION: Action handlers contained in an `events` object are deprecated in favor of putting them in an `actions` object (error on <Ember.Route:ember352>)
at Object.triggerEvent (http://localhost:8000/vendor/ember/index.js:30519:13)
at trigger (http://localhost:8000/vendor/ember/index.js:29641:16)
at handleError (http://localhost:8000/vendor/ember/index.js:29903:9)
at invokeCallback (http://localhost:8000/vendor/ember/index.js:8055:19)
at null.<anonymous> (http://localhost:8000/vendor/ember/index.js:8109:11)
at EventTarget.trigger (http://localhost:8000/vendor/ember/index.js:7878:22)
at http://localhost:8000/vendor/ember/index.js:8180:17
at Object.DeferredActionQueues.flush (http://localhost:8000/vendor/ember/index.js:5459:24)
at Object.Backburner.end (http://localhost:8000/vendor/ember/index.js:5545:27) index.js:394
Error while loading route:
Object {readyState: 4, getResponseHeader: function, getAllResponseHeaders: function, setRequestHeader: function, overrideMimeType: function…}
index.js:394
Uncaught #<Object> index.js:30566
Where am I going wrong?

Your Account model is using the DS.RESTAdapter instead of the DS.FixtureAdapter, because you are setting the adapter in ApplicationAdapter, the expected is AccountAdapter. So you receive an error from the ajax, probably because the url does not match a server.
To configure the DS.FixtureAdapter per model use:
var AccountAdapter = DS.FixtureAdapter.extend();
export default AccountAdapter;
Or as global adapter for all models:
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter
});
I hope it helps

I think the real issue was that you defined your Fixture Adapter in adapters/adapter.js.
When you called:
store.find('account');
It correctly found the model but then looked for the correct adapter. You don't have an adapters/account.js so it used the application default, which has been mentioned is a RESTAdapter.
To get your example working, just change the filename.

I was getting the same error...
However I was able to fix this by importing my ApplicationAdapter, and using that to define my store:
app/adapters/application.js:
var ApplicationAdapter = DS.FixtureAdapter.extend();
export default ApplicationAdapter;
app/store/application.js:
import ApplicationAdapter from 'appkit/adapters/application';
var Store = DS.Store.extend({
adapter: ApplicationAdapter
});
export default Store;
Keep in mind I have not changed the default application name away from appkit yet, you may have to change this name or the paths to make this function properly for you.

Related

Ember database new record event and observer

My web app is built using Ember.JS and Firebase for storing data. It also serves as a backend for a mobile app. Users can use mobile app to send a 'help-request' - the app manipulates directly with the Firebase records. When the change is made admin of the web app can see the notification on the screen. That works fine. Now I want to add a sound to this notification.
My general idea to solve it to add an observer that will be triggered when a new record of help-request type is added to the database.
I found a post sort of explaining how to do it but it's using deprecated methods like ArrayControler.
I added a simple observer to help-request model that is triggered when property/ies of the record are modified. That works fine but seems to be a hack rather than a real solution.
So the big question is:
1. Is there any callback, or event, or notification that I can subscribe to check if a new record is created in the Firebase? If so how would I subscribe to it?
import DS from 'ember-data';
export default DS.Model.extend({
device: DS.attr('string'),
userName: DS.attr('string'),
locationName: DS.attr('string'),
type: DS.attr('string'),
fullNameChanged: function() {
// deal with the change
console.log("FULL NAME");
}.observes('device').on('init')
});
My Second approach:
Did Create - never called when the changes are made to Firebase directly.
didCreate:function(){
console.log("Created");
var mySound = soundManager.createSound({
url: 'assets/beep22.mp3'
});
mySound.play();
},
Did update - called but the property is not persisted
didUpdate:function(){
console.log("Updated");
console.log((this.get('shouldPlay')));
}
Did Load - seemed to be the best approach but the changes are not persisted :(
didLoad:function(){
console.log("Did load");
if(this.get('shouldPlay')){
var mySound = soundManager.createSound({
url: 'assets/beep22.mp3'
});
mySound.play();
this.set('shouldPlay','false');
this.save().then(() => {
console.log("saved");
},(error)=>{
console.log(error);
});
}
}
Update:
this.set('shouldPlay','false');
should be
this.set('shouldPlay',false);
This is how it finally worked.
When firebase adds new record into the store it's actually loaded not created. So you can use didLoad hook on ember model.
I would also suggest creating service to play sounds. It will make things easier down the road.
// models/help-request.js
import DS from 'ember-data';
import Ember from 'ember';
const {inject: {service}} = Ember;
export default DS.Model.extend({
soundPlayer: service(),
didLoad() {
this._super(...arguments);
this.get('soundPlayer').newHelpRequest(this);
},
});
// services/sound-player.js
import Ember from 'ember';
export default Ember.Service.extend({
init() {
this._super(...arguments);
const beep = soundManager.createSound({
url: 'assets/beep22.mp3',
});
this.set('beep', beep);
}
play(sound) {
this.get(sound).play();
},
newHelpRequest(helpRequest) {
if (!helpRequest.get('_didNotify')) {
helpRequest.set('_didNotify', true);
this.play('beep');
}
},
});

Ember Data usage without a Backend API and converting Models to JSON (Ember 2.5.0)

I am using Ember v2.5.0 without an external datastore.
After creating a record at the route using the createRecord method it cannot be queried for in other parts of the app (controller or components).
My understanding is that I need to use store.push to save the record locally so that it may be accessed by the controller. However the store.push method requires the arguments to be in json format.
I could just do away with the models however I was wondering if there a quick way to convert the models into json format using Ember version 2.5.0?
I would also like to know if my assumptions on using store.push to persist the data locally is a recommended way to go when using Ember Data without an external backend.
There are other references on "Ember models to json" on stack overflow however they are outdated and I particularly would like to know if my approach/assumptions are correct and if not, what the alternatives are. Im very new to Ember.
Problem
//Route
import Ember from 'ember';
export default Ember.Route.extend({
model() {
let shape, square;
square = this.store.createRecord('square');
shape = this.store.createRecord('shape', {
shared: 'shared-value',
square: square
});
return shape;
}
});
//Controller
import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
someActionName() {
console.log(this.store.peekRecord('shape', 1)); //undefined!
}
}
});
//Shape Model
import DS from 'ember-data';
export default DS.Model.extend({
shared: DS.attr('string', { defaultValue: '' }),
square: DS.belongsTo('square')
});
//Square Model
import DS from 'ember-data';
export default DS.Model.extend({
sides: DS.attr('string', { defaultValue: '4' }),
whereIbelong: DS.belongsTo('shape')
});
I don't think using store.push is a good long-term approach, it's better to use the save and destroyRecord methods, as Ember Data expects.
You can create an adapter from the base Adapter using local storage, or maybe just returning the record passed in createRecord/updateRecord works.
Experiment with it and find what works better for your use case, adapters are very flexible.
As a side note, the best way I found to make store.push work as expected is like this:
var obj = {
id: '1',
name: "object name",
// More object properties...
};
store.push(store.normalize('model-name', obj));
createRecord does not add an ID. So this.store.peekRecord('shape', 1) is undefined because your record created does not have an ID. Everything works well if you set an ID for your record.
Ember Twiddle: https://ember-twiddle.com/e2b24b5a2cdab19c7b7401c57aff9959?openFiles=controllers.application.js%2C
If your goal is to persist records on client side have a look at ember-local-storage.

What array name does Ember Data expect for sub directory models?

I recently started learning Ember and using Ember-CLI so I'm not quite well educated about Ember Data and what array names it expects for relationships that are in sub directories in my app.
// models/server.js
import DS from 'ember-data';
export default DS.Model.extend({
serverHistory: DS.hasMany("history/server", { async: true })
});
// models/history/server.js
import DS from 'ember-data';
export default DS.Model.extend({
server: DS.belongsTo("server", { async: true })
});
I've tried returning these names from my API
server_historys_ids
server_histories_ids
history_server_ids
history_servers_ids
But I don't see an XHR request for Server history in my application. The servers itself are fetched fine.
Update
I changed my relationship name and the API is returning history ids but I'm still not getting an history json request even though I'm trying to each in the template. The game relationship data is accessible in the template and a request is successfully made.
// models/server.js
import DS from 'ember-data';
export default DS.Model.extend({
// attr's here.. not relevant
// Relationships
game: DS.belongsTo("game", { async: true }), // works
serverHistories: DS.hasMany("history/server", { async: true }) // doesn't make a request like game does.
});
I also have an adapter/history/server.js but it's only telling what namespace to use - "api".
Update 2
I think the problem may be in the way I'm calling the data to the model.
// routes/server/view/index.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
var parentModel = this.modelFor("server.view");
return this.store.query("server", { server_address: parentModel.server_address });
// return this.store.find("server", 1);
}
});
How come when I use find with an id it updates the template data and when I use query with parameters it doesn't?
Update 3
So I got my find and query problem sorted out, here's the way I got it to work: https://stackoverflow.com/a/31831667/1814027
The relationship problem still persists. I see no serverHistory data in my Ember toolbar nor a request being made to the API for it.
I beleive serverHistory is anti-conventional name for hasMany and serverHistories should be instead.
export default DS.Model.extend({
serverHistories: DS.hasMany("history/server", { async: true })
});
Then in case of ActiveModelAdapter expected server payload is:
{"server": {"id": 1, "server_history_ids": [1,2,3]}}
It doesn't depend on the fact that serverHistory is namespaced model, it depends on relation name only.
For example for model:
// models/server.js
import DS from 'ember-data';
export default DS.Model.extend({
bars: DS.hasMany("history/server", { async: true })
});
expected payload is:
{"server": {"id": 1, "bar_ids": [1,2,3]}}
Update
Working ember-cli example: https://github.com/artych/so_ember_data_subdir
Artych's answer helped me on the right path but Ember didn't want to recognise server_history_ids so I just renamed the hasMany relation to histories and returned histories: [] from my API. Now it works.. don't know why but it works.

How to properly use Fixtures with ember-cli project structure

I'm using ember-cli and trying to make some sense of the structure of the app and how it is all wired together. There are some differences in the main Ember guide docs and what I'm seeing in the ember-cli generated project. I understand the API's are moving fast so I just need to be pointed in the right direction.
In router.js I have the following:
Router.map(function() {
this.route('domains', {path: "/domains" });
});
Then I have models/domain.js
import DS from 'ember-data';
var Domain = DS.Model.extend({
name: DS.attr('string')
});
Domain.reopenClass({
FIXTURES: [
{ id: 1, name: 'User'},
{ id: 2, name: 'Address'}
]
});
export default Domain;
And I have routes/domains.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.store.all('domain');
}
});
And finally ( I think ), I have templates/domains.hbs
<h1>Domains</h1>
{{#each}}
<p>{{name}}</p>
{{/each}}
Only the header is being rendered when I visit the http://localhost:4200/domains url. I'm using the ember chrome extension and I don't see any data coming back in the request. I'm not sure if it is a naming convention issue or what I'm doing wrong so any help is appreciated.
all just returns records that have already been found in the store. find will issue a request (in this case hitting the fixtures) and populate the store, and also return all of the records in the store.
this.store.find('domain');
The problem ended up being 2-fold. Kingpin2K was right in that I needed to use find instead of all. I also had to change the adapter to the following in adapters/application.js:
export default DS.FixtureAdapter.extend();

EmberCLI app errors when using fixtures

I usually use Rails for my Ember apps. However this time we opted to decouple the API from the Ember app, and as such I'm trying EmberCLI. So far it's lovely to setup and use. However when using attempting to use fixtures it doesn't load the data.
As listed in this post I am using reopenClass when declaring the fixtures.
If I do not override the model, it does not error but the Ember inspector also shows no data was loaded. If I override my file with:
// routes/campaigns/index.js
export default Ember.Route.extend({
model: function() {
return this.store.find('campaign');
}
});
And visit the /campaigns path then I get the error I get the error Error while loading route: undefined.
From what I can find this seems to happen when Ember cannot find the data.
My router and model with obvious items like export default excluded:
// app/router.js
Router.map(function() {
this.resource('campaigns', function() {
});
});
// models/campaign.js
var Campaign = DS.Model.extend({
name: DS.attr('string')
});
Campaign.reopenClass({
FIXTURES: [
{ "id": 1, "name": "Campaign #1" },
{ "id": 2, "name": "Campaign #2" }
]
});
I have tested the same setup in a Rails app I just made, and it works perfectly. I'd love any insight people could give, as EmberCLI seems lightweight and worth the effort.
Edit: Adding my app.js file to answer question about whether I included DS.FixtureAdapter:
// Import statements
Ember.MODEL_FACTORY_INJECTIONS = true;
var App = Ember.Application.extend({
modulePrefix: 'nala', // TODO: loaded via config
Resolver: Resolver
});
loadInitializers(App, 'nala');
App.ApplicationAdapter = DS.FixtureAdapter({});
export default App;
You need to set up your application adapter located at the filepath adapters/application.js as follows:
export default DS.FixtureAdapter.extend({});
See the first paragraph under ember-cli Naming Conventions. N.B. you won't need to import DS or Ember if you're using ember-cli and have them listed in your .jshintrc file.