How to make updates in DOM elements more efficient? - javascript

I'm making a collaborative browser text editor and I have some optimizations concerns. The goal is to allow users to edit files arbitrarily long. When someone updates the file, everyone receives an update notification, which updates the editor content.
I'm interested to know what happens under the hood with the code bellow: does the program deallocates the old value content and allocates the new one every time this function is called? Ideally, what I would like to do is to have something like a 'file buffer', then I would just move the contents around as the users insert new data into it. But I don't want to lose the convenience of using the textarea element with its events and stuff.
function updateTextAreaValue(new_value) {
var my_textarea = document.querySelector("#my_textarea");
my_textarea.value = new_value;
}

The contents of a textarea are just a string. Setting a new value releases the string it used to contain (making it eligible for garbage collection), and stores the new one.
You've said you don't want to lose the convenience of a textarea element because of its "events and stuff," but a contenteditable div will have the same events, and also a DOM structure within it that you can adjust rather than replacing the entire string. And since it's HTML, it has styling, etc.
But of course, if a textarea serves your needs...

Related

vaadin readding component creates new element in dom

In Vaadin when readding a component that was removed previously will create a new element in the DOM.
Lets look at it in detail
Button button = new Button("test");
button.getElement().executeJs("""
this.addEventListener("click", event => {
alert("hello");
});
""");
add(button);
now after some event on the server we decide to remove the component from the view. So the corresponding element in the DOM gets removed.
then after another event we add the button component again. so vaadin creates a new Element on the client and adds this to the DOM. (the new element is missing the eventlistener)
What I would expect to happen is that vaadin reuses the same element that existed before. But it does not. normally this would not really matter, but in our case we added a eventlistener with js. (yes we could add eventlisteners on the javaside, but let’s suppose that we really need to do it in js because we want to execute some code on the client)
why is vaadin doing this, and is there an option so vaadin uses always the same element.
In pure JS I could easily just create a lookup table with the element that I removed, and then later use the elements in the lookup table to add them again to the DOM. Doing this would keep all the event listeners for the element.
What really perplexes me, is that even though the element in the DOM is different everytime, the Element I get with component.getElement() is always the same. Isn’t this element supposed to represent the element on the clientside?
Of course we could just run the same js on the element everytime we add the element to the view, but that is quite cumbersome.
Is vaadin doing this because of performance reasons. What are your explanations for this behaviour?
This is indeed a mechanism to avoid leaking memory. A mechanism based on server-side reference tracking would be significantly more complex, work with a delay (because the reference is cleared only when GC runs), and make it more difficult for the developer to control what happens. The current design makes it easy for the developer to choose what should happen: hide to preserve it in the browser, detach to let it be garbage collected.
I could also clarify that the same DOM element is reused in cases when the component is detached and then attached back again during the same server visit.

Update linked file in photoshop via java

I am trying to write a script that will go through every smart object and essentially do the same thing as if I were to open it and then hit the "Layer>Smart Objects> update all modified content". My goal is to create a script that will iterate over every smart object within every smart object; effectively updating all the smart objects recursively.
For example, say I have a single .png that is an image of a pebble. I created a linked smart object out of that, then made some duplicates, then make smart-objects from those, made duplicates of those pebble groups, etc. until I had a mountain. The idea of my script is to iterate through every nested smart object down to that single pebble and update the linked content; so If I change my pebble, I can run the script to then update the entire mountain. Does that make sense?
Here lies my problem though: I am very new to photoshop javascript, and I don't know where to even start with this. ideally I want to loop through the layers, open each smart object found in them, do whatever it takes to update the linked content, then repeat that on all the objects within that object, etc.
i know some c#; and if i was coding this in c# it'd be a foreach loop function that calls itself foreach smart object, like this pseudo code:
void updateeverything(document)
{
foreach(layer OBJ in document)
{
//magic happens on this line to do the same thing as the "update changed content" button in the UI
if(OBJ.type().tostring() == "smartobject")
{
updateeverything(OBJ)
}
}
}

What kind of information can I get out of an "input" event? Is there a better way of tracking text changes?

I am trying to capture changes to a text area and decipher what changes were made to the text.
I am doing this to somewhat copy the behavior of a 'tag-able' editor such as the one on Facebook - where you can 'tag' your friend or a public page.
My plan is to track the indexes of 'tagged words' in the string input (with some object containing data about the placement of the 'tagged words'). So this means that whenever a word/phrase is typed/pasted into the textarea, I want to know exactly what changed in the text to update the indexes of the 'tagged words'.
I ran into an event that seems to fit my need:
textAreaEl.bind("input", function (e) {});
To proceed with this, I want to be able to figure out what exactly changed in the text to trigger this event .. from the 'e' object.
Is there a way to decipher what actually happened to the text before and after this event triggered? I took a stab at it, but came up empty. (e.which was even undefined after I entered something from the keyboard).
Also, is there a better way of tracking a string of characters in a larger string?
You can find the position (indexed at 0) of a string inside of another string using string.indexOf().
To find the complete text input of a text area or input, use element.value.
To detect when a textarea is modified, you can play around with addEventListener.
If you want to modify the contents of the textarea by changing coloration etc of its contents, that's much more difficult and I would even recommend using a div element with contenteditable instead.
Some references:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
Edit: Read your question a bit more slowly, and seems like what you're doing is you're trying to see if you can detect what changes were made. However, the purpose of this seems like you want to see what tags were added, and therefore this becomes a x/y misconception.
You don't need to exactly check what changes were made, all you need to do is check the input again every time they press a new key (or even only check for the # key). To explicitly find the difference between before and after is not needed.

Saving and reloading a DIV structure with values on page load/unload

I have a <div id="populated"> element on the page which receives dynamically created content, including populated DIVs, text areas, input texts and check boxes. Moreover, there are some elements with addEventListener.
My question is: how to save this "populated" DIV and reload it when a user returns to the page?
What I've tried, by using localStorage:
Save the entire DIV as a serialised object (got tips from here). Problem: "Uncaught TypeError: Accessing selectionDirection on an input element that cannot have a selection."
Save the entire DIV as innerHTML. Problems: 1) bind events are lost 2) already entered data in textareas/inputs is lost.
I can rebind the events, but parsing the DIV structure and storing/restoring .value for each element seemed too complicated.
I'm using "pure" JavaScript (no frameworks) and without AJAX. Any ideas, keywords?
There are basically three ways to persist data on the web:
Server-Side
Local Storage
Cookies
Now cookies have a finite limit to how much they can store (and IIRC that limit varies by browser), so if your DIV has a decent amount of stuff in it, cookies won't cut it. Local storage works for newer browsers ... if it works at all that is (you should really post your storage error as a separate SO post of its own).
As for what to store, you can basically give up on storing bound events ... unless you want to convert every one to an in-line attribute (eg. "onclick='...") and save all the HTML ... but that would be a terrible idea because inline events quickly become a nightmare. (If you only have one or two this might be an option ... but I wince at suggesting it.)
What is commonly done instead is that you serialize your data in to an structure that just contains the data (no DOM, no events, etc.). You store that (however you choose), and then when you want to "load" it you deserialize it, building any DOM elements you need and hooking up any events you want at that point. JSON.stringify (present in newer browser's, or available via Crockford's JSON library if you want to support older ones) is one option for doing this serialization, as is jQuery's serialize and serializeArray methods. Or you can roll your own solution.
So in short:
Serialize just the data you want to save (via JSON.stringify, $.serialize or $.serializeArray, or your own function)
Choose from server-side (the common approach), cookies (limited space) or local storage (only on newer browsers and you'll have to solve your error) to store it
When you get it out of storage, deserialize it, building DOM elements and binding events to those elements as needed.
Hope that helps.
It took some redesign, but I managed to solve the problem:
The structure of the DIV is stored as innerHTML on onpageonload in localStorage.
The values of the fields inside the DIV are serialised and stored in localStorage.
The binding function is independent and can be called so it parses the whole DIV.
On onbeforeunload the scrips goes through the DIV as saves the "inner HTML" and the values. While loading, the scripts checks if localStorage is empty: if not, populates the DIV, loads the values and rebind the events.

Is it more efficient to keep DOM elements on the page or to re-render them as needed?

I have a dialog box that has settings associated with it. When the user clicks the "settings" button, a form is displayed so they can modify them.
What is more efficient:
to have the settings div exist hidden on the page and display when needed
OR
to create the settings div and populate it with data when needed?
In the first scenario you don't need to create the DOM elements and populate them every time, but if there are many dialog boxes open at once (a common situation) then the amount of elements on the page is pretty large and many of them are not going to be used often. But in the second situation, elements are created and appended to the DOM which gets expensive.
I'd suggest you to "cache" your html on the page, but enforce browser to do not render it until necessary (until user request the data, or simply scroll to it). The main idea is to add your html (with data) to the page, but comment it out. For example,
<div id="cached-html">
<!--
<div>
...some custom html here
</div>
-->
</div>
Then once user requested the html, you can do the following:
var html = document.getElementById('cached-html'),
inner = html.innerHTML;
html.innerHTML = inner.substring(4, inner.length - 4);
Pros. is that you don't bother your browser with initial rendering (later you can simply user display:none to hide it again), so your page renders faster.
And another note - if your data (and as a consequence inner html) changes frequently, then it will be better to re-render it each time user request it, but if it is almost static, then hide/show should be more effective.
There can be problems either way, it depends on your page. If you already have a lot of elements on the page, it may be better load add them when you need them. If your page is already very "scripty" you may want to load the elements and show them when needed.
The real question is what would be better for your page, more script, or more dom elements.
When you have to display same setting div at multiple places.
Keeping that hidden is a better solution.
Remember that creating a new dom element or cloning a existing dom element gives almost same performance, but for code clarity/maintainence cloning or template is better.
Implementation using template: Make a template of div setting and keep that hidden:
<div class="template_setting">
Your settings(children of template_setting)
</div>
Javascript/Jquery code:
-Whenever someone opens a dialogue box, make a clone of childrens of template_setting and append to div_dialogue.
-As you may have multiple templates on the same page( which is not always true).
Apply a custom event on the id of newly created setting div.( keep id of each setting div different, you can increment each one by some character/number).
$('#dialogue_opener').click(function(event){
$('.template_setting').children().clone().appendTo(div_dialogue)
.trigger('adjustSettingID');
Consider a hybrid solution. Load the "settings" div after the page is ready. This way, the user won't feel the extra "expense", and you'll have the div ready for when you need it.
I've typically seen that rendering from JavaScript is pretty darn fast. I've built lots of "just in time" menus, grids, and forms and the users can't tell the difference. The nice thing about it is that you don't have to keep a form current, just blow it away and default everything to the data in you settings object. Makes for cleaner code in my opinion.

Categories

Resources