Caching / moving markup in the DOM for reuse - javascript

Bit of a weird one - bound to see some head scratching and wrinkled noses on here.
Currently developing this scrollable timeline that has users incrementally loading new modules of HTML via AJAX as they pan / scroll, so before long they can end up with quite a bit of markup on the page. As they "zoom" though (i.e. shift the scale of the timeline's X-axis), I'm having to destroy that newly generated markup and establish a new frame of reference into which new modules can be loaded.
Without getting too deep into the how and why of the timeline's inner workings, I'd like to know if there's a way in JavaScript / jQuery to cache or temporarily "move" (not just remove and rewrite) chunks of markup you've already loaded into the DOM.
I have a feeling this is wishful thinking on my part, but if anyone's put some thought into this before, I'd be interested to hear. Thanks in advance.

Instead of using .empty() (which it sounds like is what you're doing), you can use .detach(). The caveat with using .detach() is that you have to store a reference to the detached element(s) so you can, say .append() it later. Like this:
...
var elementCache = [];
...
// later
elementCache.push($('some-selector-here').detach());
...
// later still
$('some-other-selector').append(elementCache.pop());

Related

knockout and applyBindings - how to control the scope?

I am new to knockout, so going to fire a lot of questions. But I'm not new to data binding. So I am knocking my head on the difference between my expectations and reality. Here is a very basic question about applyBindings.
It looks like applyBindings has the parameter "view model", which is to me the domain object graph (as javascript objects) plus perhaps additional helper things added for the purpose of the view creation. But what I am completely missing at first is the scope of the bindings! I expected this to be applied to the current parent DOM element. But no, it is applied globally, in the entire page!
So is the expectation that in one HTML document there can only ever be one view model? This is very surprising to me! How am I supposed to create a single page web app where I have one panel showing the address book, another panel showing my appointments, another panel showing one loan application to review, and yet another showing the underwriting of another loan? They are all completely different things, am I really supposed to link them all into a single view model???
In my expectation, you bind a javascript object to a DOM element, and everything in there renders it. With every new nested DOM element, the focus object may change. It may be flowing out of some foreach binding from the parent's object. But then two sibling (or cousin) DOM elements might be sitting side by side and having completely different view model, and also a different life cycle. Like while I am in my underwriting workflow, I quickly need to bring up an address book or my calendar. All of it in a single page app. There should be no global interference between different view models used by different unrelated DOM elements.
And yet here we are with knockout I see it has only one ko.applyBindings(viewModelObject) for a the entire page.
What am I missing? What is preventing us from modifying ko.applyBindings to take two arguments, the view model-object and the DOM element in which to show it? I could try doing that, but I am afraid if knockout has been designed in this global mindset, there might be lots of issues running the knockout machinery more than once on the same page?
I'm sorry if I am frustrating people by shooting an answer already. But since I have a very urgent project I need to try to resolve my issues ASAP, and I am reading the knockout source code, which is quite nicely organized and uses good names, so it's quite intelligible; therefore I have found the answer myself.
The answer is that, yes, you can applyBindings to a parent element that you choose. The document.body is only the default if you don't say anything.
Therefore, from now on, I shall (tell my team to) always call applyBindings with the second argument specified for the rootNode. Like this:
<div>
... all my UI elements for this thing ...
... then last element in this div:
<script type="text/javascript">ko.applyBindings(viewModelObject, document.currentScript.parentElement);</script>
</div>
so, that way I can have multiple view models each in their own DOM element.
And additionally also, I was wondering, does knockout not somehow assign the model object to the DOM element? I could do that in my script tag too:
<div>
... all my UI elements for this thing ...
... then last element in this div:
<script type="text/javascript">
const viewElement = document.currentScript.parentElement;
viewElement.viewModelObject = viewModelObject;
ko.applyBindings(viewModelObject, viewElement);
</script>
</div>
and this allows me then -- if only for debugging -- to find the current view model object on the DOM element that is the root of a view. (It would be nice if that would happen with all other descendant bindings too, but that is perhaps the subject of another question.)
In fact, I decided to put into our general configuration a hard replacement of the ko.applyBindings function:
ko._applyBindings = ko.applyBindings;
ko.applyBindings(viewModelObject, rootNode, extendContextCallback) {
rootNode = rootNode || document.currentScript.parentElement;
rootNode.viewModelObject = viewModelObject;
ko._applyBindings(viewModelObject, rootNode, extendContextCallback);
}
now I don't even have to convince my team to do it this way, they will automatically, even without being aware of it.

Using html tags vs javascript create element

I'm trying to get a grasp on html and javascript and wondering if there is a functional difference between using document.createElement(some_tag) vs <some tag></some tag>. I can see how using javascript's create element might make it easy to create the specific element over and over in different pages/sections of the website (instead of copying and pasting and making your code bulky). But is it bad practice/bad for memory or something to use create element.
For instance, consider the following code:
function createhtml() {
var li1 = document.createElement("li");
var text1 = document.createTextNode("First List Item");
li1.appendChild(text1);
var ul1 = document.createElement("ul");
ul1.appendChild(li1);
document.body.appendChild(ul1);
}
<body onload="createhtml()">
</body>
Is it better to do that, or simply:
<ul>
<li>First List Item </li>
</ul>
Or are they both exactly the same, and the second one is just easier/faster to type.
I've found that keeping things separated will save you a lot of frustration down the road. Defining the objects on your page should go in your HTML, styling and animating those elements should go in your CSS and making things do stuff should go in your javascript. Of course, this isn't a hard and fast rule but keeping things separated by intention makes it easier to read and easier to find what you're looking for. Additionally, in response to which method is faster, the pre-assembled HTML is going to load faster than trying to assemble it in js on the fly.
TLDR; create the elements in your HTML whenever possible.
Your page/browser will:
draw the static HTML
go get the JavaScript and run it
redraw the new elements into the page
In your example here that's a trivial thing that a user would never notice, but on larger pages it can cause issues. The JavaScript method is also less efficient in terms of your time and processing efficiency.
Generally speaking, you would want to use JavaScript when you have to generate something that might be changing after the page loads (eg click stuff, do stuff), or different based on circumstances that are present when it loads (eg go get a list of stuff from elsewhere). Static/unchanging material is better off left as HTML.
For the HTML typed, the page will load and your list will be visible.
For the JavaScript version, the page will load, your script will be parsed and run and then the list will be visible.
This is a very trivial example, but straight HTML will be slightly more performant and for static content, much more maintainable.
For your example if you know the number of elements before then using static html tags are better option because it will take time and memory to append to the body.
where in other case if you don't know how many elements are going to be appended to the body then you have to use dom.
you can see the performance and memory that your elements going to take can be see in the developers tool "F12" timeline.

How to avoid locking my HTML structure when using jQuery to create rich client experiences?

I've had this happen to me three times now and I feel it's time I learned how to avoid this scenario.
Typically, I build the HTML. Once I'm content with the structure and visual design, I start using jQuery to wire up events and other things.
Thing is, sometimes the client wants a small change or even a medium change that requires me to change the HTML, and this causes my javascript code to break because it depends on HTML selectors that no longer exist.
How can I avoid digging myself into this hole every time I create a website? Any articles I should read?
Make your selectors less brittle.
Don't use a selector by index, next sibling, immediate child, or the like
Use classes so even if you have to change the tag name and the element's position in the HTML, the selector will still work
Don't use parent() or child() without specifying a selector. Make sure you look for a parent or child with a specific class
Sometimes, depending on the amount of rework, you'll have to update the script. Keep them as decoupled as possible, but there's always some coupling, it's the interface between script and HTML. It's like being able to change an implementation without having to change the interface. Sometimes you need new behavior that needs a new interface.
I think the best way to help you is for you to show a small sample of a change in the HTML that required a change to your jQuery code. We could then show you how to minimize changes to JS as you update the HTML

Replace whole DOM in javascript

I need to implement undo-redo functionality in my project. But it is very complex and every change affects on many elements. I think saving and restoring whole page will be the best choice. But i have some problems with missing .data() params of DOM elements. I use next functions:
// save
var documentCopy = document.documentElement.cloneNode(true);
// restore
document.replaceChild(
documentCopy,
document.documentElement
);
How I can save and restore whole DOM with saving jQuery.data() of elements?
The trivial thing that I would try is using jQuery's clone instead. Be sure to use it with two true parameters, but be careful as this may be very very slow. Are you sure this is the only way to achieve what you want? Can't you replace a smaller portion of the document?
Note that this doesn't seem to work well with document.documentElement, and that using it with the document's body seems to lose the data on the original elements (say what?). Here's a small test.

Idiomatic Dojo that does the same thing as YAHOO.util.Event.onContentReady?

I want to start manipulating a DOM element as soon as it's available, to minimize the time that it might appear in its original state on screen. I know in YUI you'd use YAHOO.util.Event.onContentReady and I'm pretty sure you'd use bind in jQuery. I'm new Dojo, and I'm not sure: What's the "Dojo Way" to do this?
UPDATE: I specifically don't want to wait for the whole page (which is ridiculously data-heavy; the markup alone is potentially a MB or more) to load. I want to immediately start looking for the element in the DOM and start processing as soon as it's there, without waiting for ALL the markup to download, be parsed, and inserted into the DOM—that could take a relatively long time. I want to start looking at the DOM and get to work as soon as this tiny fragment is there. Given that constraint, isn't dojo.ready a poor fit? My understanding is that it waits for the entire DOM to be ready, similar to onDOMReady.
The most precise way of injecting functionality after a piece of DOM is added to the tree is to have the <script> that requires it placed directly below it in markup. It seems less sexy than something like onContentReady, but onContentReady is just a polling mechanism that may end up executing your callback around the same time as domready, anyway, long after the relevant DOM subtree is ready for scripting.
Browsers can assemble a DOM tree pretty fast. And with a polling solution such as onContentReady, you're slowing down the page assembly/render by having to execute the code that searches for the targeted element(s) every few milliseconds.
I'd stick with keeping your <script>s at the bottom of the <body> or if you must, putting the must-run-now-damnit code in a <script> after the required markup.
I am not familiar with dojo's API, so I can't answer your specific question wrt dojo if the above is not helpful.
(edited to escape the leading < in tags so they would display)
dojo.addOnLoad. There is also a newer alias dojo.ready.
note: Add on load also waits to be sure all required modules are loaded, in addition to waiting for DOM-readyness
dojo.addOnLoad() is what you want. See documentation.
Note that dojo.ready() is just an alias for that method.

Categories

Resources