Compound Javascript Elements - javascript

I've got this page I'm doing some tests in Javascript and jQuery: JS Tests
I've got a few questions on how to create, not sure if this is right term, but compound controls via Javascript. In something like Flash, you'd create the Object class, have the getters and setters, draw your images, etc. In JS, it seems to be a very different thought process. My main question is How do you create multiple elements with getters and setters to be rendered, filtered, and interacted with in Javascript?
The main code regarding this example sits with:
var html = (function(){
// var FRAG = $(document.createDocumentFragment());
htmlBox = $(document.createElement("div"));
var eTitle = $(document.createElement("h4"));
var ePrice = $(document.createElement("p"));
// set class first
htmlBox.addClass("box")
htmlBox.css({
backgroundColor : color
})
// set text values
eTitle.text(title);
ePrice.text("$" + price);
htmlBox.append(eTitle)
htmlBox.append(ePrice)
return htmlBox;
})();
... inside the Box() class. If someone could take a look at the source and let me know what isn't quite right, that'd be great.
EDIT
Here's the final result for this example. Some logistics to work out, but what I'm after.
http://geerswitch.in/tests/obj/
As for the jQuery creating nodes, the built in JS version works fine for this, and some research on Google shows that the non-jquery way is faster in most cases anyway (and looks worse, imo)

You're doing it almost right. You've created a Box class to represent your higher-order UI element, you're instantiating it for each element, and your main program is manipulating the elements through its interface. The only thing you're missing is the split between the public interface and the private implementation. There's nothing to prevent me from doing myBox.price += 10 right now, even though the Box interface clearly implies that price should be set at construction and never modified.
JavaScript doesn't have visibility modifiers like "private" and "public", but you can create the same effect yourself. Check out Douglas Crockford's explanation for the details. Crockford is an opinionated genius when it comes to JavaScript, and he's the brains behind JSLint and JSON.

Related

Strange javascript behaviour - error unless 'classes' are defined in correct order

I have a very strange problem with javascript and easel js.
I am using the easel.js library and am already fairly far into the construction of a project using it.
I am attempting to have a 'class' (I know they aren't technically classes in javascript but I will use this terminology for lack of a better word) inherit the Shape class from easel js, and then have another class inherit that. So it would be something like this:
easeljs.Shape --> MenuButton --> BuildingButton
The code I am using looks like this:
BuildingButton.prototype = Object.create(MenuButton.prototype);
BuildingButton.prototype.constructor = BuildingButton;
function BuildingButton(){
MenuButton.call(this);
}
MenuButton.prototype = Object.create(createjs.Shape.prototype);
MenuButton.prototype.constructor = MenuButton;
function MenuButton(){
createjs.Shape.call(this);
}
The problem is that I get the following error with this code:
Uncaught TypeError: undefined is not a function
easeljs-0.7.1.combined.js:8439
(line 8439 is pointing to the initialize() function in the Shape() constructor).
now here's the strange thing. If I change the order of the definitions so that the sub class is defined second and not first, it works fine!
MenuButton.prototype = Object.create(createjs.Shape.prototype);
MenuButton.prototype.constructor = MenuButton;
function MenuButton(){
createjs.Shape.call(this);
}
BuildingButton.prototype = Object.create(MenuButton.prototype);
BuildingButton.prototype.constructor = BuildingButton;
function BuildingButton(){
MenuButton.call(this);
}
This is very confusing as I can't seem to figure out why on earth this is happening. I could just make sure I define them in the correct order and leave it be, but I have all my 'classes' in different source files which are then strung together by grunt, which does so alphabetically.
Also, I feel like I may have a big gap in my knowledge of javascript (or maybe easel.js I'm not sure what exactly is causing this behaviour).
Thanks in advance for your help and I hope the question makes sense!
MenuButton.prototype = Object.create(createjs.Shape.prototype);
…
BuildingButton.prototype = Object.create(MenuButton.prototype);
These two statements have a clear dependency and need to be executed in the correct order (for the function declarations the order is irrelevant if placed in the same scope/file, but if in different files they need to be loaded in the correct order obviously).
I have all my 'classes' in different source files which are then strung together by grunt, which does so alphabetically
That's not a good idea. You should use some build tool/script that allows the declaration of dependencies.
Read this to clear things out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
In first example you try to inherit from nothing, since MenuButton.prototype is not yet defined. To make it work just add MenuButton.prototype = new createjs.Shape.prototype(instead of Object.create() wich shouldn't be used anymore) to instantiate it first before you can you use it. Your first code is like you are willing to eat a banana before having one.

JavaScript to jQuery for KendoUI

I've been using KendoUI and have been using they're command functions. However to call JS I must call named jS functions. No huge deal. When I use the "This" key word it brings back the entire grid and I mus find a value of a child from a sibling of the same parent elements and i wound up doing this ugly thing. The question I have is how can I turn this "thing" into something jqueryable readable and comprehensible
function AddRole(e) {
var $ParentNode = e.target.parentNode.parentNode.children[1].children[0].getAttribute("value", 0);
}
Sorry, but you have other problems.
If you rely on such a structure e.target.parentNode.parentNode.children[1].children[0], your Markup and JS do not scale at all.
Use the oppurtunity to create scalable and consistent code. Or at least, set some id, class or html5 data attribute on the children[0] element in order to identify it properly.

Why shouldn't I access elements more "directly" (elemId.innerHTML)

I've seen some JavaScript code to access HTML elements like this: elementID.innerHTML, and it works, though practically every tutorial I searched for uses document.getElementById(). I don't even know if there's a term for the short addressing.
At first I thought simplistically that each id'ed HTML element was directly under window but using getParent() shows the tree structure is there, so it didn't matter that elements I wanted were nested. I wrote a short test case:
http://jsfiddle.net/hYzLu/
<div id="fruit">Mango<div id="color">red</div></div>
<div id="car">Chevy</div>
<div id="result" style="color: #A33"></div>
result.innerHTML = "I like my " + color.innerHTML + " " + car.innerHTML;
The "short" method looks like a nice shortcut, but I feel there is something wrong with it for it practically not appearing in tutorials.
Why is document.getElementById() preferred, or may be even required in some cases?
Why shouldn't I access elements more “directly” (elemId.innerHTML)
Because, according to the others in this thread, referencing arbitrarily by id name is not fully supported.
So, what I think you should be doing instead is store their selections into a var, and then reference the var.
Try instead
var color = document.getElementById('color');
color.innerHTML = 'something';
The reason why this would be a good thing to do is that performing a lookup in the DOM is an expensive process, memory wise. And so if you store the element's reference into a variable, it becomes static. Thus you're not performing a lookup each time you want to .doSomething() to it.
Please note that javascript libraries tend to add shim functions to increase general function support across browsers. which would be a benefit to using, for example, jquery's selectors over pure javascript. Though, if you are in fact worried about memory / performance, native JS usually wins speed tests. (jsperf.com is a good tool for measuring speed and doing comparisons.)
It's safer I guess. If you had a variable named result in the same context that you are doing result.HTML I'm pretty sure the browser will throw a wobbler. Doing it in the way of document.getElementById() in this instance would obviously provide you with the associated DOM element.
Also, if you are dynamically adding HTML to the page I may be wrong, but you could also encounter unexpected behaviour in terms of what result is :)
Also I will add that not all ID's can have values that will not work as variable names. For instance if your ID is "nav-menu".
Although I suppose you could write window["nav-menu"].innerHTML
Which makes me think, what happens if you create a window level variable with the same name as an ID?
Checkout this jsfiddle (tested in chrome): http://jsfiddle.net/8yH5y/
This really seems like a bad idea altogether. Just use document.getElementById("id") and store the result to a variable if you will be using the reference more than once.

Never store intermediate program state in DOM?

I managed to run into this funny bug the other day where too quick modifications of the DOM caused the entire internet explorer to crash. So i was thinking, why am i even setting these values if i'm going to change them later anyway? (the modifications are very unpredictable so completely avoiding the scenario is impossible)
Some background, my website is more like a game/application and has alot of custom elements etc. Performance is key and moving around and modifying objects should be fast, smooth and without flicker. In one iteration tons of objects can have their state modified.
The objects in my application right now follows something similar to this pattern. domElement is the actual element used in the DOM, created with document.createElement or getElementById.
function SetWidth(w) {
this.width = w;
this.domElement.style.width = w + "px";
}
Obiously an object has more styles than just width but just to simplify things. This works pretty well right now but what if i for some reason set the width of one object twice inside one "program loop". This will mean the DOM will be modified twice but it's only the second state that should be displayed. In most new browsers this doesn't make a difference because the page is not rendered until all user javascript has completed. But in some browsers you can get updates unpredictably anytime. And even if there is no visible change, does it impact the performance?
Another problem is that some elements depend on being attached to the DOM before you can set/get some properties on them which you can easier avoid with the pattern below.
What i was thinking of doing instead was going back to the old-school render-loop pattern.
So the above object would look like this:
function SetWidth(w) {
this.width = w;
this.stateChanged = true;
}
function Render() {
if(this.stateChanged)
this.domElement.style.width = this.width + "px";
}
Once the "program-loop" is done you loop through every object only to "render" them (or use some more sophisticated structure keeping track of all modified objects).
To me this seems like defeating the whole purpose of having the DOM as you are basically reinventing what is already in place but sometimes it feels like it doesn't work properly so you have to roll your own version.
Has anyone used something similar and is it worth it? What are the pros and cons? What else do i have to think of? Adding and removing objects and managing z-index also should be taken into consideration.
One of the things to watch out for is that if you request the value of property that is dependant on the layout, the browser will recalculate the layout to get the value, which may take a significant amount of time. So "this.style.width = '80px'" will be quick but "this.style.width = '80px'; var wid = this.clientWidth;" will take much, much longer. Of course, if you use the setWidth/render pattern above, you won't be able to get the value of
clientWidth until after the render phase.
The setWidth/render pattern is a reasonable one for your use case, but I'd create a sub object to hold the pending layout values rather than storing them directly on the 'this' object. If you empty/recreate the sub object at the end of the render step, you won't need to store a separate stateChanged variable, the presence of the property in the sub object can serve that purpose.

Override "private" function in JavaScript

I'm monkey-patching some of the jQuery's Draggable code*.
The goal is to avoid modifying the original source files and patch dynamically one of the internal functions.
The function _generatePosition is declared like this:
(function($) {
$.widget("ui.draggable", $.ui.mouse, {
...
_generatePosition: function(event) {
...
}
}
})(jQuery);
Is it possible to achieve the dynamic replacement of it?
*So it calculates the snapping grid relative to the top of parent element and not relative to the top of element being dragged. See here for more details.
You can manipulate individual instances:
.draggable().data("draggable")._generatePosition = function() {};
Or modify the prototype, affecting all instances:
$.ui.draggable.prototype._generatePosition = function() {};
You can actually modify these, but only on a per-element basic as far as I know. But you could easily create your own $.fn.draggable wrapper, and just call the original wrapper and run this: draggableElement.data('draggable')._generatePosition = fn
As Jörn Zaefferer pointed out, you could also modify the draggable prototype, by using $.ui.draggable.prototype._generatePosition = fn
Edit for below comments: It seems you can edit these (after the last widget re-write), but I would still steer clear. Here's an example of the base method, you can modify from there if you wish, but keep in mind this can and probably will break in a future release. Also any "inheritors" of the widget won't pick up these changes, not sure if that's an issue.
As for the reason, to deny you access isn't the reason really (not in this case). In library cases like this it's more to be clean than deny you access, or because the library may want to change architecture later, and still break as few people as possible when they do so...letting you only access the "public" members of their code gives the authors more flexibility in changing anything that's "private".
Case in point: jQuery UI 1.8 moved a lot of code into the position utility, allowing a lot of private code cleanup that you didn't see happen, since it was all private before this allowed a fairly big optimization/code reduction without breaking people left and right.

Categories

Resources