I am trying to work out how best to split up my Ember.js statechart into multiple files.
Using SproutCore we needed to use SC.State.plugin('statename') to associate a state we defined in another file with our main statechart.
I saw no such functionality in Ember, so instead I simply added a new state to my statemanager's states hash. (See also my jsFiddle)
App.statemanager = Ember.StateManager.create({
stateOne: Ember.State.create(....)
})
// new file:
App.statemanager.states.stateTwo = Ember.State.create(....)
At first this seemed to work -- I was able to transition to the new state I defined. However, I discovered that I was not able to transition out of this state using an action:
App.statemanager.states.stateTwo = Ember.State.create({
doSomething: (manager) {
manager.transitionTo("stateOne");
}
)}
App.statemanager.send("doSomething"); // throws error when trying to transition
The error I get locally is
Uncaught Error: assertion failed: You need to provide an object and key to `get`.
Ember.StateManager.Ember.State.extend.findStatesByRoute
The error I get in my jsFiddle is
Uncaught TypeError: Cannot read property 'length' of undefined
Ember.StateManager.Ember.State.extend.contextFreeTransition
Ember.StateManager.Ember.State.extend.transitionTo
Does anyone know why this is happening, and what the correct way to break up a statechart is?
Instead of trying to edit or add to an already created State Manager you should build up the individual states and then combine them all when building your state chart.
For example: http://jsfiddle.net/a6wHt/5/
App.Statemanager = Ember.StateManager.extend({
initialState: 'stateOne',
stateOne: App.StateOne,
stateTwo: App.StateTwo,
stateThree: App.StateThree,
stateFour: App.StateFour
});
Also, I used extend to build the 'class' and then instantiated at the end with create. I think it is a good idea to get in the habit of doing this, even if you treat your state chart as a singleton. It makes your code easier to test later down the line.
Related
I have need in my Ember.js app to render a different component based on some piece of data. I've set this up via the component helper, like so:
<article class='awesome-article'>
{{component article-type}}
</article>
This works all fine and well, though naturally, if the article-type attribute doesn't match the name of any component in the application (which may happen due to fat-fingering), it gives us a nice, explicit error message:
Uncaught Error: Assertion Failed: HTMLBars error: Could not find component named "nonexistent-component" (no component or template with that name was found)
This is also great, but now I've got a smaller problem: I'd like to gracefully handle this error in the application, but I can't seem to figure out how to either catch or prevent this error. I've tried adding an error action to the parent component, but it skips right past it.
How can I go about handling this? This is probably one of those "missing something obvious" things, but my Google-fu has failed me this time.
You could create a handlebars helper that looks up if the component is registered in the container and based on this information you can display it or display some placeholder component.
If you are on at least Ember 2.3 you can use the public API they added: http://emberjs.com/api/classes/RegistryProxyMixin.html#method_hasRegistration
I am creating a new ember app. I want to use the newest version of ember-data. (ember-data 2.0). I want it to be a mobile webapp. Therefore it must handle variable network access and even offline.
I want it to store all data locally and use that data when it goes offline so the user gets the same experience regardless of the network connectivity.
Is ember-data 2.0 capable of handling the offline case? Do I just make an adapter that detects offline/online and then do....?
Or do I have to make my own in-between layer to hide the offline handling from ember-data?
Are there any libraries out there that has this problem solved? I have found some, but are there any that is up to date with the latest version of ember-data?
If device will go offline and user will try to transition to route, for which model is not loaded yet, you will have an error. You need to handle these situations yourself. For example, you may create a nice page with error message and a refresh button. To do this, you need:
First, In application route, create error action (it will catch errors during model hook), and when error occurs, save transition in memory. Do not try to use local storage for this task, it will save only properties, while we need an actual transition object. Use either window.failedTransition or inject in controllers and routes a simple object, which will contain a failed transition.
actions: {
error: function (error, transition) {
transition.abort();
/**
* You need to correct this line, as you don't have memoryStorage
* injected. Use window.failedTransition, or create a simple
* storage, Iy's up to you.
*/
this.get('memoryStorage').set('failedTransition', transition);
return true; //This line is important, or the whole idea will not work
}
}
Second, Create an error controller and template. In error controller define an action, retry:
actions: {
retry: function () {
/**
* Correct this line too
*/
var transition = this.get('memoryStorage').getAndRemove('failedTransition');
if (transition !== undefined) {
transition.retry();
}
}
}
Finally, In error template display a status and an error text (if any available) and a button with that action to retry a transition.
This is a simple solution for simple case (device gone offline just for few seconds), maybe you will need something way more complex. If you want your application to fully work without a network access, than you may want to use local storage (there is an addon https://github.com/funkensturm/ember-local-storage) for all data and sync it with server from time to time (i.e sync data every 10 sec in background). Unfortunately I didn't try such things, but I think it is possible.
I have a application with a Django backend and an AngularJS front-end.
I use the angular-gettext plugin along with Grunt to handle translations.
The thing is, I sometimes received dynamic strings from my backend through the API. For instance a MySQL error about a foreign key constraint or duplicate key entry.
How can I add this strings to the .pot file or non harcoded string in general ?
I've tried to following but of course it cannot work :
angular.module('app').factory('HttpInterceptor', ['$q', '$injector', '$rootScope', '$cookieStore', 'gettext', function ($q, $injector, $rootScope, $cookieStore, gettext) {
responseError: function (rejection) {
gettext('static string'); //it works
gettext(rejection.data.error); //does not work
$rootScope.$emit('errorModal', rejection.data);
}
// Return the promise rejection.
return $q.reject(rejection);
}
};
}]);
})();
One solution I could think of would be to write every dynamic strings into a JSON object. Send this json to server and from there, write a static file containing these strings so gettext can extract them.
What do you suggest ?
I also use angular-gettext and have strings returned from the server that need to be translated. We did not like the idea of having a separate translation system for those messages so we send them over in the default language like normal.
To allow this to work we did two things. We created a function in our backend which we can call to retrieve all the possible strings to translate. In our case it's mainly static data that only changes once in a while. Ideally this would be automated but it's fine for now.
That list is formatted properly through code into html with the translate tag. This file is not deployed, it is just there to allow the extraction task to find the strings.
Secondly we created a filter to do the translation on the interpolated value, so instead of translating {{foo}} it will translate the word bar if that's was the value of foo. We called this postTranslate and it's a simple:
angular
.module('app')
.filter('postTranslate', ['gettextCatalog', function (gettextCatalog) {
return function (s) {
return gettextCatalog.getString(s);
};
}]);
As for things that are not in the database we have another file for those where we manually put them in. So your error messages may go here.
If errors are all you are worried about though, you may rather consider not showing all the error messages directly and instead determine what user friendly error message to show. That user friendly error message is in the front end and therefore circumvents all of this other headache :)
While in any particular case there are hints and clues on how to debug an error you get, I haven't really found a general Ember strategy.
For example, a typeError while loading a route:
Assertion failed: Error while loading route: TypeError: 'undefined' is not an object (evaluating 'window.router.lander') (ignore the fact that I'm trying to access window.router.lander. It's irrelevant)
Why does Ember not tell you which route it's loading when this error happens? Or whether it happens in afterModel(), or activate()? And what's the general strategy for finding that sort of context info?
So far all I've got is adding a bunch of console.logs scattered around. For example with the error above:
1) Find all occurrences of window.router.lander in my code
2) before the first occurrence, add a console.log('is it the first occurrence?'), and after the first occurrence put a console.log('its not the first occurrence')
3) Do the same for every occurrence
4) refresh. One of the 'is it the nth occurrence?' won't have a closer, and now you know where the error happened.
For better debugging, you can enable transitions logging by create app with LOG_TRANSITIONS and/or LOG_TRANSITIONS_INTERNAL properties:
window.App = Ember.Application.create({
// Basic logging, e.g. "Transitioned into 'post'"
LOG_TRANSITIONS: true,
// Extremely detailed logging, highlighting every internal
// step made while transitioning into a route, including
// `beforeModel`, `model`, and `afterModel` hooks, and
// information about redirects and aborted transitions
LOG_TRANSITIONS_INTERNAL: true
});
Referenece: http://emberjs.com/guides/understanding-ember/debugging/
Also, you can use canary build which provide detailed error stack:
http://emberjs.com/builds/#/canary
Ember isn't particularly helpful when it comes to errors in the model hook, or the promises it returns. I'm sure I've read in one of the issues (or http://discuss.emberjs.com/ I'm not sure) that this is an open issue in which they're working.
What I do is use the Chrome Developer Tools to debug the issue (instead of just console loggin it). From my experience it's usually:
you're not returning anything in the model hook
an error inside one of the then functions on the promise the model hook returns
I hope it helps you!
I am trying to learn ember.js and i started by trying to set up a simple (not so simple) mouseover, out, down example for myself.
http://jsfiddle.net/RBbpS/48/
I keep getting a "Uncaught Error: assertion failed: Unable to find view at path"
Can someone shed some light on this I am sure it is something simple.
Your first fiddle works if you declare the App as a global (without the var).
http://jsfiddle.net/Sly7/RBbpS/52/
That beeing said, if you're new to ember, I advice you to starts with reading emberjs.com (do not forget the api:), where you can find what are the handlers for a view
from the doc:
Mouse events: 'mouseDown', 'mouseUp', 'contextMenu', 'click', 'doubleClick',
'mouseMove', 'focusIn', 'focusOut', 'mouseEnter', 'mouseLeave'
Finally, the version you use here is a quite old one, I suggest you to try the latest release: http://cloud.github.com/downloads/emberjs/ember.js/ember-latest.js (do not forget to include also http://cloud.github.com/downloads/wycats/handlebars.js/handlebars-1.0.rc.1.js
Try mouseEnter and mouseLeave instead mouseOver and mouseOut . Refer the ember.js view events guide