We are using version pre4 of ember.
We have a framework (SignalR) working parallel with ember that handles real-time notifications to our application. In the older versions of ember we were able to access the global reference of the router / controller. But with the new version of Ember this is no longer possible. (This is fine)
We have tried different approaches like setting up a global controller in the top route:
setupController: function(){
app.appController = this.controllerFor('app');
}
and sending an event to this controller, which bubbles up to the route like this:
notificator.update = function (context) {
app.appController.send('notificationOccured', context);
});
But this feels like working against the Ember team which just removed the global references.
So now to the big question: is there a better way to access the router or a controller from outside Ember? Preferably send an event to either with a context.
All help is appreciated!
So now to the big question: is there a better way to access the router or a controller from outside Ember? Preferably send an event to either with a context.
Yes. This sounds like a good fit for the ember instrumentation module. Have an appropriate controller subscribe to SignalR events, then trigger them whenever your app handles real-time notification.
First, add a method to ApplicationController for processing updates. If not defined here the event would bubble to the router.
App.ApplicationController = Ember.Controller.extend({
count: 0,
name: 'default',
signalrNotificationOccured: function(context) {
this.incrementProperty('count');
this.set('name', context.name);
}
});
Next, setup your ApplicationController by subscribing to the signalr.notificationOccured event. Use the before callback to log the event and send it's payload to the controller.
App.ApplicationRoute = Ember.Route.extend({
setupController: function (controller, model) {
Ember.Instrumentation.subscribe("signalr.notificationOccured", {
before: function(name, timestamp, payload) {
console.log('Recieved ', name, ' at ' + timestamp + ' with payload: ', payload);
controller.send('signalrNotificationOccured', payload);
},
after: function() {}
});
}
});
Then from your SignalR Application, use Ember.Instrumentation.instrument to send payload to your ApplicationController as follows:
notificator.update = function (context) {
Ember.Instrumentation.instrument("signalr.notificationOccured", context);
});
I posted a working copy with simulated SignalR notifications here: http://jsbin.com/iyexuf/1/edit
Docs on the instrumentation module can be found here, also check out the specs for more examples.
You probably shouldn't be doing this but here's a way to get access to the application's controllers, views, models and router instances. When your application is initialized, controllers, views, models and router are all registered in the application container __container__
APP.__container__.lookup('controller:foo').get('content');
APP.__container__.lookup('view:foo').get('templateName');
APP.__container__.lookup('router:main');
What i think you should do is encapsulate calls to the 3rd party library inside Ember and let Ember manage the whole application. See this attempt to make JQuery UI ember-aware
Related
i have a getrank button which is supposed to make get request to the server
So for this i wrote a Getrank function in controller inside which i have this
var self = this;
this.store.find('post',"1").then(function(data){
self.set('mydata',data);
console.log(self.get('mydata'));
},
function(error){
alert(error);
})
It returns a class.,instead i need a json to work on
Is it a normal behaviour or am i doing something wrong?
If you need a JSON response use jQuery's getJSON method. Ember-Data gives you client side records that it manages with a plethora of additional functionality.
Ember and Ember Data are two different products and Ember works just fine without Ember-Data using POJOs
I have a again which I can't answer for my self properly, maybe because of my lack in expierience with EmberJS.
I have to develop a management interface in EmberJS, using Symfony 2 for the backend, which should act and feel like a desktop application. So far so good, but since alot of people will work with the data inside this application, i would really like to use a WebSocket adapter implementation for EmberJS, since every connected client should always know about changes in entities immediately (or asap). I could write a WebSocket adapter for EmberJS but my problem here is that the WebSocket will do much more then RESTful operations, also the server will send messages without any EmberJS request (e.g. an entity changed and the server broadcasting this change to all clients). That means that i need a "command" structure on top of RESTful operations which, as far as my expierience goes, will not work with a pure DS Adapter.
For example:
Maybe i will trigger a controller method that will send a websocket message like this:
{command: "say", parameters: {message: "Hello guys!"} }
This command is not Entity (DS) related and will never go into the application store.
Another example would be like this:
{command: "load entity", parameters: {type: "Vendor\Bundle\Entity\Type", id: 43} }
Which would load an entity which should be stored in the application store.
Well, as i said, im not that familiar with EmberJS that I could figure out which the best approach could be. Should I bypass the DS Adapter completely and check for "isDirty" and just the push methods after loading entities? I'm happy about any idea you have!
As far as I understand your question, you want to push changes from your backend to your single page app?
You can push custom JSON into your application's store in Ember by using self.store.push('modelName', json). Have a look at the docs for a better undestanding.
So for example if your server sends you JSON via websocket that looks like this
{
- "message": {
"type": "fooModel",
"data": {
... // Model attributes here
}
}
}
you can push the data into your store. The following snippet would work with SocketIO for example:
App.ApplicationRoute = Ember.Route.extend({
activate: function() {
// connect to the websocket once we enter the application route
var socket = window.io.connect('http://localhost:8080');
var self = this;
socket.on('message', function(data){
self.store.push(data.type, data.item);
});
}
});
You can easily modify this snippet to fit your needs.
I'm using Ember 1.4 with EmberData beta 7. The routes in my application are fairly straight forward and looks like this. ScenarioController and StratsControllers are ArrayControllers. StratsStratController is an ObjectController.
App.Router.map(function () {
this.route('scenarios', {path: "/scenarios"});
this.resource('strats', {path: "/"}, function() {
this.route('strat', {path: "/strat/:strat_id"});
});
});
When I first transitioned into the 'strats' route, Ember calls the findAll method, which makes a request to my server for all 'strat' instances as expected. My server returns all data associated with the 'strat' model, side loading all related hasMany records. Then I transitioned to the scenarios route, and Ember calls findAll to fetch all 'scenario' instances, which was also as expected. However, when I transitioned back to the 'strats' route via the browser's back button, I see another GET message from Ember to my server requesting all 'strat' instances again. This surprised me. Why did Ember make another call to findAll for the 'strat' instances when it already has it in DS.store? Is this expected behavior?
I think its because its a live array of data, so ember checks to see if anything has changed in the mean time. You can change the data to a static array using the toArray() method but the way it is currently means that any updates to the database are automatically reflected on the client.
I have just come across this in the docs:
FINDING ALL RECORDS OF A TYPE
1
var posts = this.store.find('post'); // => GET /posts
To get a list of records already loaded into the store, without making another network request, use all instead.
1
var posts = this.store.all('post'); // => no network request
find returns a DS.PromiseArray that fulfills to a DS.RecordArray and all directly returns a DS.RecordArray.
It's important to note that DS.RecordArray is not a JavaScript array. It is an object that implements Ember.Enumerable. This is important because, for example, if you want to retrieve records by index, the [] notation will not work--you'll have to use objectAt(index) instead.
I am trying to simulate a slow backend in a test application using FIXTURES. I am doing the following:
App.SlowIndexRoute = Ember.Route.extend({
model: function() {
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(function() {
resolve(App.Node.find());
}, 2000);
});
}
});
I was expecting that this would behave similarly to a slow REST backend, namely:
The request is sent
Route is activated, and the template is rendered
Reply arrives from backend
Now the data is updated in the template
Instead, this is roughly what is happening, as far as I can tell:
The request is sent
No rendering of the template is performed, the route is not yet activated.
Once the reply "arrives" (resolve(App.Node.find());) the route is activated
The template is rendered, and since the data is already available, it is also displayed
How can I more accurately simulate a slow REST backend? How can I make sure that the router is activating the view/template before the reply arrives?
DS.FixtureAdapter has a latency property that defaults to 50 milliseconds. You can change this by instantiating the adapter manually when you create your store.
App.Store = DS.Store.extend({
adapter: DS.FixtureAdapter.create({ latency: 1000 });
});
As of Ember 1.0.0-rc.6, it is expected behavior for a route to wait for the model's promise to resolve before transitioning. If you don't want the route to wait, don't return a promise (something with a then method) from your model hook. Return a regular object, one that's already loaded, or a proxy. Then load the model later, in your setupController hook, for example.
Trying to understand better about ember's register and inject.
Basically my code looks like this:
//creating a service
Nerdeez.Wormhole = Ember.Object.extend({
...
})
//registering this service as a singleton
App.register('wormhole:current', Nerdeez.Wormhole, {singleton: true});
//wanting to inject this service to be available everywhere in my application
//especially in the adapter where i use it in the ajax hook
App.inject('App', 'wormhole', 'wormhole:current');
//when trying to access this service in the ajax hook in the adapter i get undefined WTF!
App.get('wormhole') === undefined //true
i just want this service available globally in the entire application as a singleton, what is the best way to achieve this?
it's important to say that i manage to inject my service to models, views, and controllers and the problem is injecting it to my adapter.
Thanks in advance
I couldn't figure out a way to inject the object into App either, but you can inject it into the adapter (or store) just like you can with for route & controller objects:
// register
App.register('wormhole:current', Nerdeez.Wormhole);
// inject into adapter
App.inject('adapter', 'wormhole', 'wormhole:current');
// inject into store
App.inject('store', 'wormhole', 'wormhole:current');
// inject into routes & controllers
App.inject('route', 'wormhole', 'wormhole:current');
App.inject('controller', 'wormhole', 'wormhole:current');