Is calling a bunch of HTML in a JS function bad practice? - javascript

Here's what I'm trying to do:
I am doing a few things to my text input via "oninput=myFunction()"
When I start typing I wanted to do a few things:
I have the function removing a few elements and adding a textNode already, however, I need it to add 35-40 lines of HTML as well.
Would this be bad to do?
I'm not exactly sure how I should set it up to call this HTML through the function yet.
What's the best/cleanest way to go about doing this?
Should I just keep the HTML wrapped with a hidden display:none class, and have the function add a visible class?
I feel like that wouldn't be the best method, so that's why I'm here asking!
Any advice is appreciated. I'm typing on my phone so sorry if I wasn't very clear.

The better way in my opinion is have a script that will add your event handler after the element is ready (after page load). This function should take care of creating and removing any element that are part of the script on the fly.
Doing this will make sure your HTML is clean and that the JavaScript will do what it is responsible for. There are good ways to create HTML with JavaScript by using methods such as document.createElement and document.createTextNode. When your elements are created, you can append them in the right positions.
To help get the best rendering on all browsers, it is usually a good practice to make your elements display: none before everything is ready to display.

Related

Is there a better way to do innerHTML?

I want to know if there is a better way to be doing innerHTML than what I do here. The way I am doing it is causing problems because of the fact that I can't have triple nested quotes. along side that, it is really hard to look at and manage. Thanks!
function buttonClicked(buttonValue)
{
switch (buttonValue)
{
case 1:
soundFolders.innerHTML = "<li onClick='buttonClicked(11);'>Thunder 1</li> <li onClick='buttonClicked(13);'>Light Rain 1</li> <li onClick='buttonClicked(0);'>Back</li>";
break;
case 11:
if(!thunder1Control)
{
thunder1.play();
var thunder1Control = document.createElement("li");
soundList.appendChild(thunder1Control);
thunder1Control.innerHTML = "<h3>Thunder 1</h3> <button class='stopSound' onClick='thunder1.pause(); thunder1.currentTime=0; thunder1Control.parentNode.removeChild(thunder1Control); '>X</button> <button class='volDown' onClick='thunder1.volume -= 0.25;'>-</button> <button class='volUp' onClick='thunder1.volume += 0.25;'>+</button>";
thunder1Control.setAttribute("class", "playingSound");
}
P.S. Do you guys know why the thunder1Control.parentNode.removeChild(thunder1Control) is not working?
To your first question about another way to approach this type of code, "best" is a matter of opinion so I won't really try to address what is best. But, I will give you some alternatives:
Avoid putting code into strings in your HTML. There are all sorts of limitations with that and you generally want to separate code from presentation anyway.
Install event handlers in your code with obj.addEventListener() instead of putting event handlers and code in your HTML.
Use classes and IDs or DOM queries from a particular point in the hierarchy to retrieve specific objects in your page rather than trying to save references to them in global variables. In plain javascript, element.querySelectorAll() is pretty powerful.
In many cases, it's much simpler to just hide and show blocks of HTML using obj.style.display = "none" and obj.style.display = "block" than it is to dynamically create and destroy HTML and this has the added advantage of the HTML is all specified in the page and doesn't have to be shoehorned into a javascript string.
For large blocks of dynamic HTML that wouldn't work well with hide/show for whatever reason, you can dynamically load snippets/templates of HTML from your server using ajax or you dynamically create the HTML using javascript. My first preference is generally hide/show and then if that isn't practical for some reason, it depends upon how much the HTML I want to insert varies based on the state for whether I'd rather load a template or create it dynamically using javascript. If you have large blocks of HTML you have to fit in your javascript, it is messy with quoting, etc... - no way around that if you go that route other than using one quoting scheme for the JS string delimiter and the other in your HTML.
In your particular case, it sure looks like the hide/show method would be simple.
To your second question, this line of code:
thunder1Control.parentNode.removeChild(thunder1Control)
does not work because the thunder1Control variable is long, long out of scope when your click handler is executed because it's a local variable in your buttonClicked() clicked function.
When you put code into a string as part of HTML, it is evaluated in the global scope only so any variables that it tries to reference, must themselves be global in scope.
I'd suggest that you NOT put code into strings in your HTML like that. Use references to actual javascript functions. In that particular case, I'd have to see your HTML to know how to best advise you. If there is only ever one thunder1Control, then I'd suggest you just put an id value on it and retrieve it with document.getElementBtId() when you need it rather than trying to save a reference to it in a variable.
There are essentially two other ways that I can see:
Use a framework that helps with this kind of things. Others have
mentioned jQuery. A commenter is arguing that it might be overkill
to include a framework for just this. I would argue that if you're
doing any javascript at all, you should be using a framework to
make it less terrible. But continue onto suggestion 2 if you
disagree!
You can create each of the elements via plain old javascript and append it to the elements that you need, instead of inserting it directly into innerHTML. ex.
var li = document.createElement("li");
soundFolders.appendChild(li);
etc...
But, honestly, use jQuery with some of the suggestions from others. It's pretty small, and it will heavily clean up all of your javascript. Include it via Google and it will likely already be cached in the users browser.
https://developers.google.com/speed/libraries/devguide#jquery
I think a better alternative is to use jQuery, and then instead of using .html() (equivalent of innerHTML in jQuery), you can create a template with your html and use .load() instead. Works nicer and it's cleaner. And you don't have to worry about triple nesting quotes as you said.
Edit: I'm not sure why I'm getting downvoted so much here... The poster doesn't want to worry about triple nesting quotes. A simple and, to me, elegant solution is to use .load() and to create a template, rather than a really long string of html...

Cross-browser JavaScript to alert on DOM being modified within a DIV?

I am a basic JavaScript hacker and not an advanced programmer and I would appreciate some pointers.
I am after a JavaScript (or JQuery) function that can monitor the DOM and alter if the content within a specified DIV has been changed. I want this new content captured in a variable for further processing (but for now should be echoed to console.log or alert to demonstrate success).
The DIV is content that will be updated by a separate AJAX process or may contain an iFrame, neither of which I will have full control over. The content may be updated multiple times and on an infrequent and unstructured basis. The contents of the DIV may also change format and could contain any sort of content.
I believe I need a JS event to handle this (rather than any sort of interval based check) and I have been looking at the DOMsubtreeModified function, but not only can't I make it work consistently, it appears that this is not reliable across browsers and I need this to work regardless of the client.
Am I barking up the wrong tree? Is this possible in a cross-browser way? Should I continue to hack on DOMSubtreeModified to try and get it working or is there a better method?
DOMSubtreeModified is the right event.
This might help you, I created it after reading your question. I think it does what you want it to do.
<div class="change_event_box">
1234
</div>
<script>
$(document).ready(function() {
$('.change_event_box').bind("DOMSubtreeModified",function(){
alert('changed');
});
setTimeout(function() {
$('.change_event_box').text("4321");
}, 5000);
});
</script>
http://jsfiddle.net/F4FMk/

Is it possible to create a new dom using select parts from another dom? Or prune away unwanted parts

I'm wondering if its possible to load a html page but only display a few select parts of it.
Two possible approaches come to mind:
1) Delete parts of the dom I'm not interested in.
However I wouldn't know what all those parts are, I'd only know the parts I'm interested in.
Is it possible to find the parts I'm interested in then remove everything else?
2) Create a new dom which has been made by extracting parts of the dom from the original.
Is it possible to somehow create this in parallel to the existing dom and make the browser switch to this new dom? Or alternatively create a html page from this new dom and then load that?
Are these crazy ideas? Any simple / alternative solutions?
Well the two easiest ways would probably the following.
Don't load the undesirable parts. By this, I mean that if you know what parts you
don't want to display then just remove them from the HTML. This isn't always an option,
but it is certainly the best if only have a set amount of choices.
Hide elements via CSS. You can do this by setting display: none on an unwanted
element.
Yes, just use JavaScript/jQuery.
First you have to add the jquery library to your website as a javascript link like so.
<script src="jquery.js" type="text/javascript"/>.
You would need to create a function similar to then you would put an onclick event on a link.
<script>
function switch(){
$("#button").onclick(function()
{
$(".classOfCertainElements").css("display", "none");
$(".classOtherElements").css("display", "inline");
});
}
</script>
Click me
Does that help?

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

Set variable to HTML elements with certain class?

I'm sure there is a way to set a JavaScript variable to any HTML element with a certain class attached to it? I'm just not sure how to write it. Can anyone help me out?
The best way would be to use a framework, such as jquery, that makes an easy use of (css) selectors, e.g, to select all elements with class my-class do
$('.my-class')
and then apply any code to the list of those elements
edit: don't forget to use the $(document).ready wrapper
you could simply go var x = document.getElementById('somediv'); for example. Now whatever style class pertains to somediv will of course still obtain unless you change it programatically in your javascript.
Hope that helps -- might be able to be more helpful if you give a broader context of what you are trying to accomplish.
To do this without document.getElementsByClassName('myclass') nor $(.'myclass') would be difficult and require some advanced tactics. You would have to recursively generate a list of all DOM objects from the document. While generating the list, every element touched would have to be tested for .className = 'myclass'. This is essentially what jquery does behind the scenes, although I believe on page load it caches the whole DOM for easier querying.

Categories

Resources