I am building an ember app and it is starting to get large. Is there any way to do lazy loading of the ember files so that it does take 10+ seconds to load when the user first hits the site? For example since I have several logically separate modules as part of the site, I could load the modules as they are accessed. I am using ruby on rails and the ember-rails gem.
If you think about what Ember is actually doing to render that code, you can understand why it is slow. Suppose you're creating 2k view instances, and rendering 2k templates. Templates that for the most part are doing very little. Especially if you don't care about data binding.
For a first stab, let's stop rendering through templates. This code uses itemViewClass to render each item with a custom view instead of the view used internally by each.
// Use with {{each item in items itemViewClass=App.SpanView}}
App.SpanView = Em.View.extend({
render: function(buffer) {
buffer.push("<span>"+this.get('content')+"</span>\n");
}
});
JSBin: http://jsbin.com/enapec/35/edit66
With render over-ridden, we need to interact with the render buffer ourselves.
Even faster would be getting rid of the view entirely. I think there are two ways to do this. You could create a custom view with a render method that loops over all the items, and pushes each element onto the buffer. I think given the previous example you can get that going yourself.
Another simple option is to use a helper. A dumb helper like this is more difficult to wire up for re-rendering when the list changes, but sometimes it is the right solution.
// Use with {{eachInSpan items}}
Em.Handlebars.registerBoundHelper('eachInSpan', function (items) {
return (
new Handlebars.SafeString(
items.map(function (i) {
return '<span>'+i+'</span>';
})
)
);
});
Live JSBin: http://jsbin.com/enapec/34/edit
Lastly, you could do this in jQuery with didInsertElement and the afterRender queue. I don't recommend it though.
Ember.RenderBuffer gathers information regarding the a view and generates the final representation. Ember.RenderBuffer will generate HTML which can be pushed to the DOM.
FYI here is the RenderBuffer API
DEFINED IN
MODULE : Ember-views
I am also new bee but I got this from some resource. Thanks.
On this Keynote on Embercamp London 2016, #wycats and #tomdale talk about the plans for improving Ember with slicing and dicing of the app. They talk about loading only what it's needed for that particular route. This is going to be great. I think that's what you wanted :)
https://www.periscope.tv/w/1mrGmzPBvQqJy#
Related
I am attempting to build a small proof-of-concept web application using the web2py framework. I'm so close, but my basic lack of knowledge of what's going on means I'm just hacking at it with pure guesswork rather than understanding what's going on. I was hoping someone on here could explain where I am going wrong...
The functionality I'm after is that the data needed to create the draggable items is held in a database table (and will ultimately form a hierarchy) with as little information held in the HTML as possible.
There's a fair bit of information for just about everything in this stack, so much so that I'm drowning in it, I don't know where to start. I suppose I should begin with what I've got so far...
The HTML:
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
...
<script>
$(document).ready(function(){
$.ajax( {
type: "POST",
url: 'dragndrop.py',
success: function( response ) {
$("#draggable7").html(response);
}
} )
});
</script>
<div id="draggable7"></div>
The dragndrop.py script:
## My main draggable spawner
selected = [row.id for row in db(db.t_user_shop_layouts.id==7).select()]
return ''.join([DIV('draggable'.join(k), _class='draggable ui-widget-content', _snap=".ui-widget-header", _snapMode= "inner", _grid= [ 80, 80 ], _style='position: relative;') for k in selected])
And, just for completeness, the model web2py script (although the column I'm interested in is the "id" column, which is auto-generated):
db.define_table('t_shop_layout_items',
Field('f_item_display_name_string', type='string', notnull=True,
label=T('Item Display Name String')),
Field('f_item_icon_file', type='upload',
label=T('Item Icon File')),
Field('f_item_parent_id', type='integer',
label=T('Item Parent Id')),
auth.signature,
format='%(f_item_display_name_string)s',
migrate=settings.migrate)
I'm forcing the db call to only pick up one row at the moment (id == 7) just to get the ball rolling, but eventually what I'd like to do is have the (db.id == db.f_item_parent_id) items shown first. Then when double-click, any (db.f_item_parent_id == this.id) children get spawned using helpers. Then I'm going to get an 80x80 grid size target to land on to set shop layout, and save to db. But all this paragraph is for later, I'm just giving you an idea of where I'm going with it.
Finally, some great tutorials that have helped me along the way, but were either not web2py (PHP seems popular for this) or not dynamically spawning (but hard-coded in the HTML, or what-have-you. If I've missed something obvious, please let me know:
An excellent fiddle: http://jsfiddle.net/robertrozas/qLhke/25/ and its stack overflow beginnings Jquery drag drop form hidden value inserting into php mysql
The web2py documentation: http://web2py.com/books/default/chapter/34/11/jquery-and-ajax
OK, hope that's enough! Any help would be appreciated!
In web2py, you do not create .py files and then use them as URLs. Instead, you create functions in controllers and have URLs of the form /appname/controller/function. See the documentation on dispatching. It is also best to use the built-in URL() function to generate URLs. Also, this should probably be a GET request rather than POST.
You might also want to look into web2py's built-in ajax() function as well as Ajax components.
Regarding your data model, if the f_item_parent_id field is a self reference, then you should define it as a reference field (i.e., type='reference t_shop_layout_items').
More generally, before proceeding further, it will probably be very helpful if you read more of the documentation, particularly chapters 4, 5, 11, and possibly 12.
I'm currently struggling with the problem of multilingualism in an SPA.
I've come up with several solutions, like building a wrapper for the resources resx files, or saving all labels in the database, but I am wondering if any of you have found some solution which automates these steps.
Are there any practices which are specific for this problem?
For a reasonable amount of literals, I suggest to save the resources in the DB or in a .RESX file in the server. When the user logs in or you detect the language that will be used, the literals are requested by the application and saved either in a collection of your translation module or in the LocalStorage of the browser (this could be a good approach for large data).
Then this module could have some methods to retrieve the messages, probably passing a key.
Using this solution you could inject this module in the viewmodels that need to show translated literals and acces them through the view:
<p data-bind="text: resourceManager.get('M01')"></a>
For large applications that would require huge localization data to be transfered, maybe some kind of modularity could be applied and only load the resources really needed for each module/section.
I don't think making recurrent requests to the server to get the translated literals is a good practise. SPA's should provide a good user experience and loading the translated literals from the server could be a blocking issue. Text is not like an image, you can render a page without all the images loaded, imagine rendering a page without the text :o
Anyway, I think the best solution would be to keep the server as repository and create a custom JS module that takes care to get data in one or multiple loads and is able to store it somewhere in the client.
I've solved my own problem, using a custom binding and i18next.
First, I've implemented i18next for translation of my labels/buttons and other resources.
Secondly, I've added a custom Knockout bindingHandler:
ko.bindingHandlers.i18n = {
init: function (element, valueAccessor) {
var translateKey = valueAccessor();
ko.utils.setTextContent(element, $.t(translateKey));
}
};
Finally you can add the following code to your views:
<span data-bind="i18n : 'buttons.cancel'"></span>
This will automatically get the correct resource, and Knockout will handle the bindings.
Hopefully this will help others struggling with the same problem.
Just wondering what the shorthand would be in Rails to do this (if any):
I have views/pages/ containing 5 html.erb files and they all use the same default layout.html.erb, with one yield statement in the middle of it (the standard setup).
Now I want one view that incorporates all 5 of those erb files above contiguously, one after the other, in place of the one existing yield statement in that same layout.html.erb.
What minimal changes would I make to the layout.html.erb to accomplish this.
(Rails Newbie - like it more than Django now).
Ah,
I see what you're saying. Try this. Have your file structure such that all the views for said controller are in one folder...
#controllers_views = Dir.glob("your/controllers/views/*.erb")
#controllers_views.each { |cv| puts cv }
Seems like that would work, I'm away from my dev box or I'd test it for you.
Hope that helps.
Good luck!
You could always have a javascript that requests the sequential yields at a time interval as an ajax request. Then just your target element change to reflect the updated information.
Alternatively load all 5 into different divisions, and have them revolve visibility, like a picture gallery. CSS3 could pull this off.
http://speckyboy.com/2010/06/09/10-pure-css3-image-galleries-and-sliders/
I'm using Rails 3 to create a project that will need a model called Sketch. I've already created a model, controller, and migration to handle Sketch - so far it just creates a 'sketch' object with a name for each sketch.
My problem is that I need to be able to attach an html5 canvas to each sketch object when it is created (or remove it when it is destroyed).
Since 'canvas' is not a datatype that will be stored in the database (like 'string', 'integer', or 'datetime'), how do I go about creating custom html components such as this that need to be treated like any other datatype in a Rails app?
I'm assuming that you would need to add the html components to a Model method and use a callback - like after_save - to initiate the component. But I'm not sure at all how to do this.
Not sure if I'm describing this well enough, so here is a very simple mockup:
I have the Raphael Javascript library in mind for the component that will do the sketching - if that helps.
If you can point me to any tutorials on this subject that would be great.
HTML5 canvases are rendered in the browser, not on the server where your ruby code is actually executed. Therefore I think it's safe to say that what you're asking isn't possible (at least in the way the question is phrased).
Instead you'll need to work with HTML, CSS and Javascript in your view to get the canvas working.
Canvas Tutorial / Reference
Hope this helps.
(On a related note, it's also considered a bad practice to mix view-related concepts in with your models.)
I am implementing a dashboard as a relative Rails newbie (more of an infrastructure guy). The dashboard will consist of multiple pages, each page of which will contain multiple charts/tables/etc. For modularity, I want it to be as easy as possible to add new charts or change views of the data.
Say one page has 5 different charts. I could have the controller do 5 separate data lookups, hold all the relevant data in instance variables, and render 5 partials, each of which touch subsets of the data. But it seems more modular to have one "index" controller action whose render has a bunch of divs, and for each div there is another controller action which does the data lookup and has an associated view partial in charge of managing the view of that data within the div.
So if I'm showing the website dashboard page which has two graphs, website/index would use website/graph1 and website/graph2 to look up the data for each and then _graph1.html.erb and _graph2.html.erb would use the controller data to fill out divs "graph1" and "graph2", etc.
Is this the right design, and if so, what's the easiest way to accomplish this? I have an approximation using remote_function with :action => "graph1" to fill out divs, but I'm not 100% happy with it. I suspect I'm missing something easier that Rails will do for me.
Version 1:
Simple method that I've actually used in production: iframes.
Most of the time you don't actually care if the page renders all at once and direct from the server, and indeed it's better for it to load staggered.
If you just drop an iframe src'd to the controller's show action, you have a very simple solution that doesn't require direct cross-controller interactions.
Pro:
dead easy
works with existing show actions etc
might even be faster, depending on savings w/ parallel vs sequential requests and memory load etc
Cons:
you can't always easily save the page together with whatever-it-is
iframes will break out of the host page's javascript namespace, so if they require that, you may need to give them their own minimalist layout; they also won't be able to affect the surrounding page outside their iframe
might be slower, depending on ping time etc
potential n+1 efficiency bug if you have many such modules on a page
Version 2:
Do the same thing using JS calls to replace a div with a partial, à la:
<div id="placeholder">
<%= update_page {|page| page['placeholder'].replace with some partial call here } %>
Same as above, except:
Pro:
doesn't lock it into an iframe, thus shares JS context etc
allows better handling of failure cases
Con:
requires JS and placeholder divs; a bit more complex
Version 3:
Call a whole bunch of partials. It gets complicated to do that once you're talking about things like dashboards where the individual modules have significant amounts of setup logic, however.
There are various ways to get around this by making those things into 'mixins' or the like, but IMO they're kinda kludgy.
ETA: The way to do it via mixins is to create what is essentially a library file that implements your module controllers' setup functions, include that wherever something that calls 'em is used, and call 'em.
However, this has drawbacks:
you have to know what top level controller actions will result in pages that include those modules (which you might not easily, if these are really widgety things that might appear all over, e.g. user preference dependent)
it doesn't really act as a full fledged controller
it still intermixes a lot of logic where your holding thing needs to know about the things it's holding
you can't easily have it be segregated into its own controller, 'cause it needs to be in a library-type file/mixin
It IS possible to call methods in one controller from another controller. However, it's a major pain in the ass, and a major kludge. The only time you should consider doing so is if a) they're both independently necessary controllers in their own rights, and b) it has to function entirely on the back end.
I've had to do this once - primarily because refactoring the reason for it was even MORE of a pain - and I promise you don't want to go there unless you have to.
Summary
The best method IMHO is the first if you have complex enough things that they require significant setup - a simple iframe which displays the module, passing a parameter to tell it to use an ultraminimalist layout (just CSS+JS headers) because it's not being displayed as its own page.
This allows you to keep the things totally independent, function more or less as if they were perfectly normal controllers of their own (other than the layout setting), preserve normal routes, etc.
If you DON'T need significant setup, then just use partials, and pass in whatever they need as a local variable. This will start to get fragile if you run into things like n+1 efficiency bugs, though...
why don't you give Apotomo a try, that's stateful widgets for Rails:
A tutorial how to build a simple dashboard
You could achieve this by using
render_output = render :action => "graph2"
But Me personally would probably wrap the code in either a shared helper or write you own "lib" under the lib directory to reuse the code with a shared template. Remember that unless you change your route.rb file any public method defined is accessible by
/controller/action/:id
Also remember to turn off the layout for the function :layout => nil (or specify at the top of the controller layout "graph", :except => ["graph2"]
Cheers
Christian
I'm not aware of any special Rails tricks for achieving this without using AJAX in the way you've outlined.
The simplest way to get the modularity you seek is to put those portions of controller code into separate methods (e.g. set_up_graph1_data, set_up_graph2_data, etc.), which you simply call from your index action to set up the variables for the view.
You can put these methods into ApplicationController if you want them available to multiple controllers.
As a side note, early on, Rails did used to have a feature called 'components' which would allow you to do exactly what you're asking for here, without having to use AJAX. From your view, you could just render another controller action, inline. However, this feature was removed for performance and design philosophy reasons.