I've looked around but have yet to find a great solution the the following problem:
I have a Backbone View tied to an el on the page that is a container element for what I'll call a "sidebar" in the traditional sense (for explanation's sake). This sidebar element's inner-html needs to change completely depending on the route. However, the position on the page never changes, and will always fill this container.
Now, for an initial prototype, I had a 1:1 relationship between this container and the view placed in it (I only coded up one route). Now however, said view needs to change based on the route as I've mentioned.
Being that these different views have entirely different html markup, response to events, etc... I had thought that I'd make sense to have a higher level view that'd swap in sub-views. Of course, one solution that would work would be to handle everything in the same view, but the necessary logic would be cumbersome (and pretty damn unwieldy).
Currently, here's what I'm thinking (and have partially implemented):
Have a top-level view for this page element.
Depending on the route, swap in the necessary sub-view.
These subviews are rendered with dust.js, where the .html template for just this component on the page is lazy-loaded via AJAX, compiled, and cached. Subsequent renders just consist of calling the cached "compiled" function with a new context.
Additionally, I was going to initialize and cache each of the subview Views within the top-level View, such that I'm only instantiating, setting up event handlers, etc.. once.
Then, depending on the route, look up the associated subview View (cached), and swap it in in-place of the current view.
Now, as I've mentioned, I have this mostly coded up and... semi-working. However, what I'm struggling with is how to have each of these subviews exist independently and handle the swapping, but keep all of the event handlers and current state to continuing to live whether the component is currently displayed or not.
Basically:
How to avoid completely destroying / re-instantiating subviews each time they're required. Maybe this operation isn't as expensive as I'm thinking it is and I should simply do the latter.
Being that the top-level View (the "manager", if you will) is tied to the container $el, how to swap in the subviews.
I'm sure there's a simple, elegant solution. I just haven't found it yet, unfortunately.
As far as point 1 is concerned I don't think it is too expensive to let the view be created each time.
For point 2 - I would recommend using Backbone.Marionette https://github.com/derickbailey/backbone.marionette. It has the concept of a Layout which lets you define different regions of your app and render/manage them individually.
I would recommend Backbone.Marionette not just for point 2 but for the way in which it allows you to manage interaction is in my opinion much better than standard Backbone.
Related
I'm developping an angular app right now for my company, but I reached a point where the app became extremely slow so I tried tunning it by using onetimebind everywhere I can, track by ...but it's faster to load at first but still laggy, it is composed of a pretty much huge nested objects, I've counted the total number of objects, it starts at 680 and can go up to +6000 for normal use of the app, oh yeah I should precise that the app is generating a form and pretty much +90% of the objects in the scope belongs to an input and are updated each time the client click(radio) keyup/change(text).
It also have like 5/6 arrays composed of objects and the array gets bigger/smaller accodring to the clients choice, and that's where it gets laggy, each time I add an object to the array, it takes like a second to render it, so I tried using nested controllers thinking that if the child of an object is updated Angular will render only this child and not all the others, but somehow the app got even slower and laggier :s (it's a bit faster when I use ng-show instead of ng-if but the memory used jumps from ~50Mb to ~150Mb)
I should also precise that the form is in a wizard style, and not all the inputs are displayed at once, the number of inputs that are displayed are between 10%-20% of the total inputs
Has anyone encountred this problem before? does anyone know how to deal with big scopes?
Sad to say, but that's intrinsic of the view rendering in angular.
An update in the model triggers a potential redraw of the entire view. No matter if you have elements hidden or not. The two way data binding can really kill performances. You can consider evaluate if you need to render the view only once, in that case there are optimizations, but I'm assuming that your form change dynamically, therefore a 2 way data binding is necessary.
You can try to work around this limitation but encapsulate sub part of the entire MVC. In this way a contained controllers only update the specific view associated to that scope.
You may want to consider using react (that has as first goal to address exactly your use case)
Have a look at this blog post for a comparison of the rendering pipeline between angular and react Js.
http://www.williambrownstreet.net/blog/2014/04/faster-angularjs-rendering-angularjs-and-reactjs/
Suppose we have two sibling react components called OldContainer and NewContainer. There is a child component inside OldContainer that contains a <video> tag, and the video is currently playing.
The user can now drag the child component (with the video) and drop it in the NewContainer, and they expect the video to keep playing while it's being dragged and after being dropped.
So the video appears to stick to the mouse position, and when dragged and dropped in the new container, it animates to its new position (again, it doesn't get paused).
How would you implement this? Can we implement this in a pure way (in line with the spirit of pure functions)?
Clarification: I could have used some other element instead of a video tag for explaining this problem. A NumberEasing element would be a better example, since it would require the props and state of the component to be preserved during and after the interaction.
Update 1: Code examples obviously would be nice, but what I'm mainly looking for is just a general description of how you would approach this problem in a "functional" way. How do you keep your view code simple and easy to reason about? Who handles the drag-and-drop gesture? How do you model the data that's fed into the views?
Take a look at this library : react-reverse-portal
What is it that you want to preserve? Is it Javascript objects that the component holds as state, or is it state in the DOM (like how long a video has played, or text selection in an input box)?
If it's just Javascript objects as state, you're better of moving the source of that state to another service (something like Flux). That way, it doesn't matter if the component gets recreated because it can be recreated with the state that was there before.
EDIT
The way to keep your view code simple and easy to reason about is to not keep state inside your components. Instead, all data that the component needs should be passed into the component as props. That way, the component is "pure" in that it renders the same output given the same props. That also makes the problem of wanting to reuse a component instance a non-issue, since it doesn't matter when the same input gives the same output.
For drag and drop, I'd suggest looking at: https://github.com/gaearon/react-dnd.
How you model the data you pass to view components is up to you and the needs of your application. The components shouldn't care, they should just expect to get data passed as props, and to render them. But the popular approach to dealing with this is of course Flux, and there are many libraries that implements Flux in different ways.
SECOND EDIT
Regarding if you have a subtree with hundreds of components that you want to move: I'd still start off by making the state external (pure components), and render that tree in a new place. That means that React will probably recreate that entire subtree, which is fine. I wouldn't deviate from that path unless the performance of it turned out to be horrible (just guessing that it might be horrible isn't enough).
If the performance turned out to be horrible, I would wrap that entire subtree in a component that caches the actual DOM tree and reuses it (if it gets passed the same props). But you should only do this when absolutely needed, since it goes against what React tries to do for you.
THIRD EDIT
About gestures: I'd start out with listening to gesture events in componentDidMount, and in the event callback call setState on the component with the coordinates it should have. And then render the component in render with the coordinates given. React won't recreate the component when you call setState but it will re-render it (and diff the output). If the only thing you changed was the coordinates, it should render fast enough.
If that turns out to be too slow, like if the subtree of that component is huge and it becomes a bottleneck to recreate the subtree of vDOM, I'd reposition the DOM node directly in a RAF-loop outside of Reacts control. And I'd also put a huge comment on why that was needed, because it might seem wierd for some other developer later.
Create a new variable using const or var. Put the instance of data using rest spread operator, update the necessary data to pass and send the data to the component without mutating the state of component.
Just like:
const data = {
...this.state.child,
new_data : 'abc'
}
tl;dr: I wonder if having lots (100+ for the moment, potentially up to 1000/2000 or more) of backbone views (as a cell of a table) is too heavy or not
The project I'm working on revolves around a planning view. There one row per user that covers 6 hours of a day, each hour splitted in 4 slots of 15mn. This planning is used to add "reservations" when clicking on a slot, and should handle hovering of the correct slots, and also handle when it is NOT possible to make a reservation - ie. prevent user click on an "unavailable" slot.
There is many reasons why a slot can't be clicked on: the user is not available at this time, or the user is in a reservation; or the app needs to "force" a delay slot between two reservations. Reservations (a div) are rendered in a slot (a cell of a table), and by toying with dimensions, hovers the right number of slots.
All this screen is handled with backbone. So For each slot I'm hovering on, I need to check wether I can do a reservation here or not. As of this moment, I use this by toying with the data attributes on the slots : when a reservation object is added, the slots covered are "enhanced with (among others) the reservation object (the backbone view object).
But in some cases I don't quite have a grasp on now, it mixes up, and when the reservation view is removed, the slots are not "cleaned up" : the previous class is not reset correctly. It is probably something I've done wrong or badly, but this is only going to get heavier; I think I should use another class of Backbone views here, but I'm afraid the number of slots and thereof of views objects will be high and cause performance issue. I don't know mush about js perf so I'd like to have some feedback before jumping on that train. Any other advice on how to do this would be quite welcomed too.
Thanks for your time. If this is not clear enough, tell me, I'll try and rephrase it.
We have a pretty complex backbone.js app with potentially thousands of views at a given time. Our bottlenecks are mostly in memory leaks from views that have not been properly removed or eventdriven rendering that re-renders views needlessly. That said, the actual number of views doesn't seem to affect much. Backbone views are pretty lightweight, so as long as you don't have too much events bound to them, it's not that big of a problem.
You might run into performance issues, but the views probably isn't the problem.
What you might want to do though, if you do use thousands of views is to stash up the initial rendering into one big ´.html()´-call. You can do this by giving each view-element an id based on the view's cid and then you concatenate the view's html strings and afterwards you use setElement on each view to find its element again.
Maybe this helps a litte bit :
https://stackoverflow.com/a/7150279/1067061
btw.: i like your avatar ;)
backbone handles everything is the least performant way for the browser. If it's not fast enough you need to stop creating and destroying templates. Caching a template is almost no help at all.
Instead of calling the render function against, save out a variable to the jquery selector and when the model changes use the cached selector to update the DOM. This will give you the largest jump in performance off the bat.
$title = null,
init = function(){ $title = this.$el.find('h1'); },
onTitleChange = function(event){ $title.html(event.value) }
I'm working on a backbone view that is performant. It can render a collection with 1,000,000 models at over 120FPS. The code is up on Github. https://github.com/puppybits/BackboneJS-PerfView There are a lot of other optimizations that can be done. If you check out the PrefView it has comments on most of the optimizations.
I have a question about div caching in ember js for views.
I am rendering a really heavy flash application as a part of a view and i want to switch between views but not necessarily have to reload the flash app from scratch. I would preferably want it to be "hidden".
Is there a way of doing this in ember
Currently i am implementing this using https://github.com/ghempton/ember-routemanager and one of the flash apps stay on /#media and the other on /#publishing
So when user goes to /#media the media.swf gets loaded and /#publishing the publishing.swf gets loaded into the container div. Each of these routes have a corresponding view class associated to them that renders the flash object tag to be rendered.
In the past, I have used jquery to hide the container div but i am searching for a cleaner solution.
It sounds like the feature you'd like is to be able to reuse a view instance and it's DOM across states. I have some ideas for how that could be done, unfortunately it's not possible right now without some nasty hacks.
Also, unfortunately with flash objects, they seem to get rerendered if you move them in the DOM or if you change their visibility. From what I can tell, to "hide" a flash object without causing a rerender, you can only move it off screen using CSS.
Update:
Here's a working jsFiddle example: http://jsfiddle.net/EE3B8/1
Unfortunately, that technique won't work for Flash objects, since moving them in the DOM will cause them to be reloaded. This would be a good way of eliminating expensive DOM creation/view instantiation.
I'm developing a JavaScript application that should render a visualization based on either settings in the URL hash or based on user interaction.
(For the moment I'm using Backbone.js for MVC but I think these questions may be considered framework agnostic ...?)
Let's say a user is looking at an application state with indicator A and indicator B selected.
The user changes indicator B to C, what happens?
Well, changing indicator should cause the model to wait for new data to be fetched and manipulated.
... and then, of course, changing an indicator will have many effects on the different views:
The available entities to show will change
The scales will change
The indicator label will change, etc, etc. ...
One question at this stage is what to do with all these dependent/computed variables?
Should the model, in this case, now also keep track of the data availability and the scale etc, based on the change of indicator? And should it hence also trigger change events for all these computed attributes?
In any case, "the main visualization controller" must now be notified about an update to the model, but how does it proceed?
In this case, there was an indicator change which should cause icons to be added and subtracted, labels to change etc. etc.
In another scenario, only the year might change. Should the Controller then run another pathway?
And in a third scenario, both year and indicators might change (for example when the initial URL hash is set) ... yet another set of functions to be triggered in chain?
I'm looking for a robust way of handling these different scenarios so that I can keep track of what should happen when. What I'm specifically interested in, is your opinion on what attributes to keep in the model and how to layout the controller functions in order to be able to render small user interaction changes to the model as well as multi-attribute changes.
I'm VERY new to backbone.js, so take my suggestion as all salt, with a slight chance of having some substance in there.
If I am understanding (one of) your concerns correctly, you do not like the idea of having a view that re-renders completely when changes are made; but you still like the idea of having just one view attached to that one model, if that is the case, can you create multiple render events and have them tied to that specific attribute change?
this.model.bind('change:propertyA', _.bind(this.renderA, this));
this.model.bind('change:propertyB', _.bind(this.renderB, this));