How to reduce number of DOM elements in SPA - javascript

I have a pretty complex SPA, with many tabs, views, grids, etc. Each of the elements are generated by backbone.js from a template.
Once an element is generated I want to keep a state of the element, so I cannot destroy it.
Obviously number of DOM elements with this approach is pretty high.
Is it worth the effort to de-attach a view from DOM tree once it gets hidden and re-attach it back once it gets shown?
Will backbone.js view DOM manipulation still work on de-attached element if I use $(this.el).find()?

One approach would is to let the views add/remove there element from/to the DOM. So that only views that are visible have there element attached to DOM. So you can write a view manager that call the render method of the view, passing a DOM element where the view will be rendered in. The manager can also call a stop method where he removes the views element from the DOM.

Related

Writing a backbone.js view method that automatically scrolls down a DOM element with CSS overflow

As the question asks. Writing a backbone.js view method that automatically scrolls down a DOM element with CSS overflow.
Say we've created a overflow div with the id="overflowdiv"
<div id="overflowdiv"></div>
and it is filled from a template with messages. I am aware of how models, collections and views connect somewhat.
Either way, you can create custom functions for views using backbone. Is there a way to use such a function to target the "overflowdiv" element so that it updates every time a fetch or any sort of update event fires that affects "overflowdiv".
If required I can provide further data to facilitate an easier awnser.
You can do something like:
$('#overflowdiv').children().last().get(0).scrollIntoView()
Put that in a method and call it after the container updates. See Element.scrollIntoView

Callback when ngRepeat/ngIf mutates DOM

I have a directive that needs to execute a callback function whenever its DOM subtree is mutated (by ngIf or ngRepeat for instance).
The directive is ideally able to be easily inserted to templates I have already made, which rules out putting an ng-init. I've looked at the documentation, and neither ngRepeat or ngIf seem to have any events. Additionally, it seems that most of the browser DOM events have been depreciated as well.
I would use a watch, but I can't think of an expression that will work, as jQuery returns a new object every time and the length of .children() might be unchanged through mutation if ngRepeat removes and inserts a node in the same $digest.
Any suggestions on how to detect any DOM subtree mutation entirely from a template-less directive?
EDIT: For more detail, I have multiple tables that have rows of data inserted with ngRepeat. Whenever a row is inserted, if the table has a resize directive, I need to add CSS to it. The resize directive is general enough to go on every table without needing any input, so I would prefer to not have to add ngInits to all the ngRepeat elements.
For anyone else looking for a solution that will usually work in situations like this, Angular recompiles all the repeated elements, even if they were already present. Thus the actual DOMNode objects are different, so you can just watch a DOMNode.

How to handle dynamically-added DOM elements for progressive enhancement without knowing the method of adding?

I have a simple script that that "progressively enhances" specific <input> elements with a draggable slider (demo of the jQuery plugin).
Additional <input> elements may be added, and the whole thing will be placed in many different scenarios (it's a pluggable frontend widget). In other words, I cannot hook onto some "Add Another Slider" button's click event, because I have no idea where those additional elements may come from (it may be a button, several buttons, some AJAX call, etc).
To handle those additional elements, currently I'm using:
// for any dynamically added elements:
setInterval(find_and_init_all_sliders_that_are_not_yet_inited, 200);
Is there a better way?
TL;DR:
I wanna run a function each time new DOM elements are added. But I have no info or control on how or where those new elements will be added.

this.$el.html vs this.$el.append

Is there a different between this.$el.html and this.$el.append when rendering templates? I'm totally new to js, backbone, etc. In the current project I'm working on, I see stuff like
this.$el.append(Project.Templates["template-library"](this.model))
in the outer view. In this case, this template is for a modal view. Then say the modal view has a row for each item to show in the modal view. Then for each of those rows, the template gets rendered like this:
this.$el.html(this.template({ libraries: libraries.toJSON() }));
Is there any difference between the two? And why append() should be used in certain situations, and html() in the other.
For me it really comes down to how you use your views' render method.
Some people like to use render as an extension of initialize, in that they only use it once, when the view first appears on the page, and often call it from initialize. With this style, you can safely use append without worrying about accidentally adding elements twice, because the render won't get run twice.
Alternatively you can design render to be used over and over again, whenever the view's element needs to change in some way. Backbone supports this style well, eg. this.model.on('change', this.render, this);. For this style, append would be annoying, as you'd constantly have to check whether elements already exist before append-ing them. Instead html makes more sense, because it wipes out whatever was there before.
With append a new element will be inserted into the $el, while html will change the content of the $el.
Using .append() will allow you to add or append something to already existing objects. Rather using .html(), it will change the entire object to new one.

Do HTML elements load even if they are not attached to DOM? What about backbone views?

If I create an image tag without actually adding it to DOM and add source to it does it still get the image and load it. I mean when I attach it to DOM do I immediately see the image without any delay?
More specifically, I'm working with backbone currently. So if I create a bunch of backbone view's and store them in an array, each holding individual image, do those images render even if I don't attach it to DOM? And when I do attach one those views to DOM. Do I immediately see the images without any delay?
this.$el.append(view.render().el); // where view object was created before and stored in an array
Is this a good prefetching strategy and what about the memory constraints?
Yes, that's a frequent (and not very good) scheme for background image loading : you add the src to an Image element but don't add it to the DOM. The browser loads it just as if it was in the DOM.
When you add the images to the DOM after they have been loaded, they're immediately rendered.
Even if you don't add the image element to the DOM tree, it's still created using the document object, so it belongs to that document. You simply can't create elements that exist independently of a document, so and as soon as the element exists the browser will request the image.
However, in the case of the view, it would depend on when you actually create the elements. If the render method creates the image element, it won't exist until right before you use it.

Categories

Resources