I don't know, if you have seen this demo-app yet: http://www.johnpapa.net/hottowel/ but once you start it, you see a really nice loading screen at the beginning like you would in any bigger desktop application/game.
So I haven't had the chance to go through the code properly myself, but I have started recently with Emberjs and I have the feeling that loading all the js-code for the whole SPA that I am building could be in the seconds area.
My question now, how would such a loading screen be possible with emberjs?
Or would there be a better way to go about that? (I somehow don't think requirejs would be a solution, though I could be wrong)
I'd like to contribute an alternate answer to this. By default, ready fires when the DOM is ready, and it may take some time to render your application after that, resulting in (possibly) a few seconds of blank page. For my application, using didInsertElement on ApplicationView was the best solution.
Example:
App.ApplicationView = Ember.View.extend({
didInsertElement: function() {
$("#loading").remove();
}
});
Please note that Ember also offers the ability to defer application readiness, see the code for more information.
Maybe it's my lazy way of doing things, but I just solved this by adding a no-ember class to my div.loading and in my CSS I added
.ember-application .no-ember {
display: none;
}
(Ember automatically adds the ember-application to the body.)
This way, you could also add CSS3 animations to transition away from the loading screen.
you can do something like this:
App = Ember.Application.create({
ready: function () {
$("#loader").remove();
}
});
in your body you set something like this
<img src="img/loading.gif" id="loader">
Alternative to using didInsertElement, the willInsertElement is a better event to perform the loading div removal since it will be removed from the body tag "before" the application template is rendered inside it and eliminates the "flicker" effect ( unless using absolute positioning of the loading div ).
Example:
App.ApplicationView = Ember.View.extend({
willInsertElement: function() {
$("#loading").remove();
}
});
Ember has an automagic loading view logic.
By simply setting App.LoadingView and its template, Ember will show that view while application loads.
This feature is likely to change in next release, in favor of a nested loading route feature which looks promising. See below:
Draft documentation
Feature proposal and discussion
In Ember 2.0 there is no more View layer, but you can do the same with initializers:
App.initializer({
name: 'splash-screen-remover',
initialize: function(application) {
$('#loading').remove();
},
});
Related
I'm rewriting some old Ember code to use closure actions, but I'm new to Ember and I can't seem to figure out how to change a sendAction that hasn't got parameters.
This is the code in the component row.js:
click: function() {
this.sendAction();
}
The row.hbs as well as the parent templates are just
{{yield}}
so I can't add anything there it seems. Does anyone know how to solve this?
If it's just {{yield}} all the way up is it possible that the click didn't actually do anything?
Usually the calling template would have something like {{row action="doSomething"}} Ember Docs
It's also possible there was some behavior here that kept sending the action up when you have a {{yield}} in which case you would want to just keep going up the tree until you found (somewhere) an action="doSomething" declaration. That is where you will start sending the action back down.
e.g.
{{top action="doSomething"}}
{{row}}
{{/top}}
Would become
{{top}}
{{row doSomething=(action "doSomething")}}
{{/top}}
Then row.js
click() {
this.doSomething();
}
Ember.View is deprecated, in favor of Components. That's great but I'm having trouble making sense of the 2.0 release.
Most often, I used the didInsertElement hook to run some jQuery code etc. But now that the Em.View class has been deprecated, how can I achieve the same thing? I don't want to create a component or anything like that. It doesn't make sense to create components for normal pages(routes). Simply because its not a re-usable thing plus component's scopes are isolated.
Say we have a about route, and when the template is rendered I just want to sun some jQuery code. How can I do this in Ember 2.0+?
You could take advantage of didTransition hook and Ember.run.next. Check my solution:
export default Ember.Route.extend({
actions: {
didTransition() {
Ember.run.next(this, 'initParticles');
}
},
initParticles() {
let ammount = (window.matchMedia('(max-width: 456px)').matches) ? 40 : 100;
particlesJS('particles-js', {
// my options
});
}
});
While it doesn't seem like the best approach, creating a component is probably your best option. Soon we'll have routeable components which will take over much of what controllers and views use to do. Creating a component and just inserting it into your template should put you on a good path to be ready for routeable components.
I encounter ugly timing problems (race conditions) with putting code which carries out layout based on height calculations with jQuery in didInsertElement().
For example, I calculate the height of a header via $('header.someClass').outerHeight(true); then I use the result to offset the content area from the top. If I render the view completely new via reloading the whole page it works (60px in my example) but if I navigate to the view from another one, it fails because the wrong height is returned (6px in my example).
To prove that it is a timing issue: If I wrap the code in:
Em.run.later(function() {
...do layout
}, 50);
It works.
I consider this a serious issue because there are not other hooks in Ember, I can attach to.
Instead you should schedule your jQuery logic to run after the rendering:
App.YourView = Ember.View.extend({
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, function(){
// perform your jQuery logic here
});
}
});
Find more infos and explanations in my blog.
It sounds like you might have a bit of a misunderstanding of how ember works.
didInsertElement is fired when that particular view is injected into the dom, not when all of the elements are in the dom. Note: If the model behind it changes, ember won't fire didInsertElement again, because it wasn't reinserted into the dom.
If it works when you delay, then it sounds like your logic for calculating the size of something is depending on something that may not be there yet.
Feel free to show an example of it using emberjs.jsbin.com.
I've tried "didInsertElement" but that didn't seem to work, the markup doesn't exist and then the jQuery plugin code executes too fast.
Would you provide a jsFiddle of your issue? Also, try doing:
didInsertElement: function() {
Ember.run.next(optionalContext, function() {
// Your code here
});
}
That will run your code at the end of the current runloop which should guarantee that all rendering and bindings have executed.
But please provide a jsFiddle so a more precise answer can be given.
Make sure you're using the inbuilt jQuery selector on the view - this.$() - that will work even if the element hasn't been inserted yet.
didInsertElement: function() {
this.$().jQueryPlugin();
}
I am building an Ember.js app and I need to do some additional setup after everything is rendered/loaded.
Is there a way to get such a callback? Thanks!
There are also several functions defined on Views that can be overloaded and which will be called automatically. These include willInsertElement(), didInsertElement(), afterRender(), etc.
In particular I find didInsertElement() a useful time to run code that in a regular object-oriented system would be run in the constructor.
You can use the ready property of Ember.Application.
example from http://awardwinningfjords.com/2011/12/27/emberjs-collections.html:
// Setup a global namespace for our code.
Twitter = Em.Application.create({
// When everything is loaded.
ready: function() {
// Start polling Twitter
setInterval(function() {
Twitter.searchResults.refresh();
}, 2000);
// The default search is empty, let's find some cats.
Twitter.searchResults.set("query", "cats");
// Call the superclass's `ready` method.
this._super();
}
});
LazyBoy's answer is what you want to do, but it will work differently than you think. The phrasing of your question highlights an interesting point about Ember.
In your question you specified that you wanted a callback after the views were rendered. However, for good 'Ember' style, you should use the 'ready' callback which fires after the application is initialized, but before the views are rendered.
The important conceptual point is that after the callback updates the data-model you should then let Ember update the views.
Letting ember update the view is mostly straightforward. There are some edge cases where it's necessary to use 'didFoo' callbacks to avoid state-transition flickers in the view. (E.g., avoid showing "no items found" for 0.2 seconds.)
If that doesn't work for you, you might also investigate the 'onLoad' callback.
You can use jQuery ajax callbacks for this:
$(document).ajaxStart(function(){ console.log("ajax started")})
$(document).ajaxStop(function(){ console.log("ajax stopped")})
This will work for all ajax requests.
I simply put this into the Application Route
actions: {
loading: function(transition, route) {
this.controllerFor('application').set('isLoading', true);
this.router.on('didTransition', this, function(){
this.controllerFor('application').set('isLoading', false);
});
}
}
And then anywhere in my template I can enable and disable loading stuff using {{#if isLoading}} or I can add special jQuery events inside the actual loading action.
Very simple but effective.