Where is my store? - ember.js

I am migrating from ember-data 0.0.14 to ember-data 1.0.0-beta.6. I have been following the guide
I am preloading some data needed by my application, triggering this pre-load when the application is ready. But I have lost the store!
/// application.js
var App = Ember.Application.createWithMixins({
...
ready: function () {
this.preLoadData();
},
...
});
/// load_data.js
function preLoadData() {
var store = this.Store;
if (DEBUG) { console.log('preLoadData > this=%o store=%o', this, store); }
store.find('node'); // was this.Node.find();
}
App.preLoadData = preLoadData;
But this.Store is not the store (I do not know what that is!). Also tried with this.store, but it is undefined, so I get:
Uncaught TypeError: Cannot call method 'find' of undefined
I have even tried doing:
// inject the store into all components
SettingsApp.inject('component', 'store', 'store:main');
Whatever that magic means (what is 'component'? Is it component 'component', or any component? What is a component?), but didn't help.
How can I access an instance of the store directly from my App?
Edit: I have found component in the documentation, but this is not what I need: I want to access the store from the App.

You are trying to access store from Application object which is not possible. You could use something like this,
var store = App.__container__.lookup('store:main')
To initialize your app
But I believe you want to initialize your app with some preloaded data. You could use initializer to do such work.
Ember.Application.initializer({
name: "preload data",
initialize: function(container, application) {
var store = container.lookup('store:main');
store.find('node');
}
});

Related

Ember component - TypeError: store is undefined

I am using ember 2.3. When I tried to access store inside a component, I am getting the following error in console.
This is what I have tried in component.js
export default Ember.Component.extend({
actions: {
saveEmployee : function() {
var store = this.store;
var newEmployee = store.createRecord("employee", {
fname: "Manu",
lname: "Benjamin",
email: "manu.benjamin#gmail.com",
department: "IT Services"
});
newEmployee.save().then(()=> {
console.log("Record successfully saved!!!!");
});
}
}
});
Do I need to include anything to use store in my component?
I was trying to figure out the reason for this type error. At last I found the solution from the following blog by Josh Farrant.
https://blog.farrant.me/how-to-access-the-store-from-within-an-ember-component/
we need to inject the store service in component.
store: Ember.inject.service(),
we can use the store injected in actions using the get function,
let store = this.get('store');
I modified my code using the above solution and it worked for me.
export default Ember.Component.extend({
store: Ember.inject.service(),
actions: {
saveEmployee : function() {
var store = this.get('store');
var newEmployee = store.createRecord("employee", {
fname: "Manu",
lname: "Benjamin",
email: "manu.benjamin#gmail.com",
department: "IT Services"
});
newEmployee.save().then(() => {
console.log("Record successfully saved!!!!");
});
}
}
});
Thanks Josh Farrant for the nice blog.
This topic has been already discussed multiple times and I am sure you can find many posts on the issue. Let me repeat shortly what has been mentioned already: try to avoid using store directly within a component.
In case your design allows you to manipulate Ember store in an associated route or a controller (where the store is btw available by default), try to send an action from a component so that it bubbles to the controller and performs a store manipulation in the controller. May
EmberJS guides - how to send actions from components help you with that.

emberjs (unknown mixin) error when working with Ember.Object.Extend

I'm creating an initializer in my ember app (using ember-cli 0.2.0 beta). In it, I define a user object (that I define with Ember.Object.extend) that I want to register and inject into the app's controllers.
When i print the user object (right after defining it) to the console, Iā€™m getting ā€œ(unkown mixin)ā€. I've looked around but can't seem to find a solution or tell why this is the case. Here's what my initializer file looks like:
// app/initializers/application.js
var currentUser = Ember.Object.extend({
authToken: localStorage['authToken'],
isAuthenticated: function () {
return !!this.get('authToken');
}.property('authToken')
});
console.log(currentUser); // logs (unknown mixin)
export function initialize(container, application) {
// register current user factory
application.register('user:current', currentUser, {singleton: true});
// inject factory
application.inject('controllers', 'currentUser', 'user:current');
}
export default {
name: 'application',
initialize: initialize
};
I would suggest using Ember.Object.create(). What's the point of extending the object but never creating an instance of it?

Accessing global application state inside a custom Handlebars helper

In an ember.js application, I'm looking for an elegant way to access global application state (e.g. configuration/session data, information about the logged in user, ect) from within a custom handlebars helper. This is easy to do in routes/controllers using Ember.Application.initializer like so:
App.initializer({
name: 'registerSession',
initialize: function(container, application) {
application.register(
'app:session',
Ember.Object.extend({userId: 1, dateFormat:"MMMM Do, YYYY", /* ... */}),
{singleton: true}
);
application.inject('controller', 'session', 'app:session');
application.inject('route', 'session', 'app:session');
}
});
However there doesn't seem to be any equivalent of this in the Handlebars helper registration api, where you can essentially inject an external dependency.
My use case for example, is that the session data holds the user's date format preference, and I have a custom helper, formatDate where I want to be able to pull in their settings to use as the default format, eg:
Ember.Handlebars.helper('formatDate', function(timestamp) {
//need to be able to access the global session data here
//in order to get the user's date format preference
return moment.unix(timestamp).format(session.dateFormat);
});
Helpers are isolated (like components), You'll need to pass in any external dependencies needed in order to use them.
Ember.Handlebars.helper('formatDate', function(timestamp, format) {
//need to be able to access the global session data here
//in order to get the user's date format preference
return moment.unix(timestamp).format(format);
});
You can if you use Ember.Handlebars.registerHelper which bring different function parameters. Once, you get the container you could look for any registered instance like your session.
I have not tested, but I think something similar to this example must work:
import {handlebarsGet} from "ember-handlebars/ext";
registerHelper('formatDate', function(value, options) {
var container = options.data.keywords.controller.container;
var session = container.lookup('app:session');
var propertyValue;
if ( options.types[0] !== 'STRING' ) {
var context = (options.contexts && options.contexts.length) ? options.contexts[0] : this;
propertyValue = handlebarsGet(context, value, options);
} else {
propertyValue = value;
}
return moment.unix(propertyValue).format(session.dateFormat);
});
Take in consideration that helpers created with this method will not re-render their content when data changes. If you need to define a "bound helper", take a look at Ember Handlebars Helpers.

Ember getting content from another controller doesn't work with local storage adapter

Getting content from another controller via this.get("controllers.index.content") or this.get("controllers.index.arrangedContent") (for sorted content) doesn't work when using the ember-localstorage-adapter on the backend.
For example, getting content from another controller:
App.StartController = Ember.ObjectController.extend({
needs: 'index',
someFunction: function() {
// get the "content" from the IndexController
var names = this.get("controllers.index.arrangedContent");
alert(names.objectAt(0).name); // should display the name property from
first stored object(if there are any stored in local storage of course),
instead, it always returns "undefined"
}
});
What am I doing wrong here? Here's an example jsfiddle
same problem as in Ember loop through content of controller
you have to use
alert(names.objectAt(0).get('name'));

Observer not firing on created object

I am trying to use observers to observe a change on my model after XHR. This is because the earlier approach of extending a fn and calling super is not allowed any more.
Running into this weird issue where my observer doesn't fire:
App = Ember.Application.create({
ready: function () {
console.log('Ember Application ready');
this.topCampaignsController = Ember.ArrayController.create({
content: null
});
App.TopCampaignsModel.create({
// Calling super is no longer allowed in object instances
//success: function () {
// this._super();
// App.topCampaignsController.set('content', this.get('data'));
//},
onDataChange: function () {
console.log('data property on the object changed');
App.topCampaignsController.set('content', this.get('data'));
}.observes('data')
});
}
});
App.TopCampaignsModel = Ember.Object.extend({
data: null,
// this will be actually called from an XHR request
success: function () {
this.set('data', [5,10]);
},
init: function () {
console.log('TopCampaignsModel created');
this.success();
console.log(this.get('data'));
}
});
Jsfiddle here: http://jsfiddle.net/gdXfN/26/
Not sure why the console doesn't log "data property on the object changed". Open to alternative approaches on how I can override the 'success' fn in my instance.
After this commit in December last year, it is no longer possible to set observers during object creation. This resulted in a huge performance win.
To set observers on create you need to use:
var Object = Object.createWithMixins({
changed: function() {
}.observes('data')
});
Here's a fiddle demonstrating this.
The API documentation should be updated accordingly, something I will do later on.
However, I don't advise you to do that, but instead set observers during object definition. The same result can be achieved: http://jsfiddle.net/teddyzeenny/gdXfN/32/
That said, there are two things you are doing that go against Ember concepts:
You should not create controller instances yourself, you should let Ember create them for you:
App.TopCampaignsController = Em.Controller.extend({ content: null });
When the App is initialized, Ember will generate the controller for you.
Models should not be aware of controller existence. Controllers should access models not the other way round.
Models and Controllers will interact together through routes.
For the last two points, you can watch the tutorial at http://emberjs.com/guides/ to see how the Application, Controllers, Models, and Routes should interact. Since you're not using
Ember Data, just ignore DS.Model and imagine an Ember.Object instead. The tutorial can give you a pretty good overview of how objects should interact.