Set an attribute for an element - javascript

I wrote a function for creating new elements. The code works correctly, but the function doesn't set that attribute for my element(my browser don't threw an error). I tried several methods but nothing worked.
function createElement(name, element, attribute, valueOfAttribute, text, indexOfChildNodes) {
name = document.createElement(element.toLowerCase());
var nodeText = document.createTextNode(text);
name.appendChild(nodeText);
var l = indexOfChildNodes;
document.childNodes[l].appendChild(name);
if(typeof attribute === 'array' && typeof valueOfAttribute === 'array'){
for(var i = 0, len = attribute.length; i<len; i++){
//name.setAttribute(attribute[i], valueOfAttribute[i]);
var attr = document.createAttribute(attribute[i]);
attr.value = valueOfAttribute[i];
name.setAttributeNode(attr);
}
} else {
return 'Check your "attribute" and "valueOfAttribute" arguments';
}
}
createElement('next', 'button', ['id'], ['next'], 'Next', 1);

It happens because typeof for arrays will never return "array" in JavaScript.
You may either use modern Array.isArray() method instead or try old-school trick with prototype:
if (Object.prototype.toString.call(attribute) === '[object Array]') { ... }
DEMO: http://jsfiddle.net/QXrwZ/

Related

querySelector vs. querySelectorAll

I have some trouble in creating a selector in javascript.
This is my code:
function __(selector){
var self = {};
self.selector = selector;
if(typeof selector == 'object'){
self.element = self.selector;
}else{
self.element = document.querySelector(self.selector);
}
// make a .css method to an element
self.css = function(propval){
return Object.assign(self.element.style,propval);
}
return self;
}
And my html file
<script src="js/selector.js"></script>
<script>
window.onload = function(){
__('p').css({'color':'red'});
}
</script>
<p>Hello</p>
<p>World</p>
<p>John</p>
The code above will only apply the .css method in the first <p> element. It's because I only used querySelector. Because querySelector only selects the first element found. And querySelectorAll selects all elements found. But when I try to change my selector to querySelectorAll It doesnt work for me anymore.
Well, the reason is querySelectorAll() returns a NodeList of the selected elements and assigning CSS to a NodeList wouldn't make much of an effect
That said, essentially you need a way to handle the case of a single element and a many in the same way
From the top of my head, a simple solution could be to always use an arrays or the NodeList and forEach() over them since both implement this method, like so:
function __(selector){
var self = {};
self.selector = selector;
if(typeof selector == 'object'){
self.elements = [self.selector];
}else{
self.elements = document.querySelectorAll(self.selector);
}
// make a .css method to an element
self.css = function(propval){
self.elements.forEach(function(element){
Object.assign(element.style, propval);
});
}
return self;
}
I'm no expert here so this can probably be optimized, but with an array/list of objects you need to loop through each one
Updated with a polyfill so this one work on at least IE11/10/9
function __(selector){
var self = {};
self.selector = selector;
if(typeof selector == 'object'){
self.element = self.selector;
}else{
self.elements = document.querySelectorAll(self.selector);
}
// make a .css method to an element
self.css = function(propval){
if (self.elements) {
for (var i = 0; i < self.elements.length; i++) {
Object.assign(self.elements[i].style,propval);
}
return;
} else {
Object.assign(self.element.style,propval);
}
}
return self;
}
if (typeof Object.assign != 'function') {
Object.assign = function (target, varArgs) { // .length of function is 2
'use strict';
if (target == null) { // TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) { // Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
};
}
<p>Hello</p>
<p>World</p>
<p>John</p>
<div>Albert</div>
<script>
window.onload = function(){
__('p').css({'color':'red'});
__(document.querySelector('div')).css({'color':'blue'});
}
</script>

What does $('#id').html(x) do differently to el.innerHTML = x

I'm storing stuff in javascript/DOM and submitting an ajax call. In the success and/or .done function when I do:
$('#results').html(data);
The javascript/DOM model becomes corrupted but when I do:
var el = document.getElementById('results');
el.innerHTML = data;
then everything works as expected. I know there isn't much information here but my question is what else is the jQuery html() doing apart from setting the innerHTML that may be effecting the state of the page.
The main reason to use the html function with a string rather than innerHTML is to prevent memory leaks or inconsistent in memory data : this function removes event handlers or other jQuery data linked to the removed elements.
If data is a string, there is no reason for $('#results').html(data); to "corrupt" your DOM more than by using innerHTML.
In Internet Explorer 9 and earlier tables in the DOM were read-only. That meant that trying to do el.innerHTML = newHTML; would result in an error being thrown if el was a TBODY, TR, etc. The jQuery .html() function handles that case for you by using a fallback method - this.empty().append(value) in the jQuery source - allowing you to use the same code for all of the browsers, regardless of version.
It may be worth taking a look at the code for the method in the jQuery source:
html : function (value) {
return jQuery.access(this, function (value) {
var elem = this[0] || {},
i = 0,
l = this.length;
if (value === undefined) {
return elem.nodeType === 1 ?
elem.innerHTML.replace(rinlinejQuery, "") :
undefined;
}
// See if we can take a shortcut and just use innerHTML
if (typeof value === "string" && !rnoInnerhtml.test(value) &&
(jQuery.support.htmlSerialize || !rnoshimcache.test(value)) &&
(jQuery.support.leadingWhitespace || !rleadingWhitespace.test(value)) &&
!wrapMap[(rtagName.exec(value) || ["", ""])[1].toLowerCase()]) {
value = value.replace(rxhtmlTag, "<$1></$2>");
try {
for (; i < l; i++) {
// Remove element nodes and prevent memory leaks
elem = this[i] || {};
if (elem.nodeType === 1) {
jQuery.cleanData(getAll(elem, false));
elem.innerHTML = value;
}
}
elem = 0;
// If using innerHTML throws an exception, use the fallback method
} catch (e) {}
}
if (elem) {
this.empty().append(value);
}
}, null, value, arguments.length);
}

I am looking for a smart way to check the object parameter passed to a function

I am in the following situation:
I have to check if the object parameter passed to a function is valid:
Exmaple:
function (opt) {
if (opt && opt.key && opt.key2) {
// make something
}
}
Is there a better way to make this kind of check?
Not really.
Unless you can use opt.pleaseReadMyMind() ;-)
You could create a method that will check if all fields have values different to null, though.
That's the most compact way of doing it.
The most correct way would be:
if( typeof opt !== "undefined" && typeof opt.key !== "undefined" && typeof opt.key2 !== "undefined") {
But as you can see that's quite a mouthful and not really necessary.
Just write a simple test routine to verify the object given a list of property names:
// usage: testProps(object to test, [list, of, property, names])
// returns true if object contains all properties
function testProps(obj, props)
{
if (obj === null)
return false;
var i;
for (i=0; i<props.length; ++i)
{
if (!(props[i] in obj))
return false;
}
return true;
}
And then in your function:
if (!testProps(obj, ['key', 'key2'])
return;
What you are doing is valid, but it does have flaws.
if (opt && opt.key && opt.key2) {
This check would fail if opt.key has falsely values [0,null,false,and so on]
In that case you would have to do a typeof check to make sure it is not undefined.
if (opt && typeof opt.key !== "undefined" && opt.key2) {
Yeah, but it's only "better" if you have a lot of keys to check, not just three. Something like this:
function opt(opt) {
for(var i = 0; i<3; i++) {
if(typeof opt["key"+((i > 0) ? "" : i + 1))] === "undefined") {
return;
}
}
// create object
}
If opt is undefined all its keys will be too, so there's an implicit check for that as well.
You could also define the variable names you want to check in array, something like this:
var propsToCheck = ["key", "key1", "key2"];
function(opt) {
for(var i = 0, ii = propsToCheck.length; i<ii; i++) {
if(typeof opt[propsToCheck[i]] === "undefined") {
return;
}
// create object
}
}
Not really much of a better solution, but it does allow for less typing if you're planning on checking more than three or four properties.
You could always do it like this:
function validate(o, args) {
if (typeof(o) == 'object' && args instanceof Array) {
for (var i = args.length - 1; i >= 0; --i) {
if (typeof(o[args[i]]) === 'undefined') return false;
}
return true;
} else {
return false;
}
}
function myFunction(obj) {
if (validate(obj, ['foo', 'bar'])) {
// Your code goes here.
} else {
// Object passed to the function did not validate.
}
}
Here's a fiddle for you: http://jsfiddle.net/reL2g/

Jquery Evolution from simple plain javascript

i have been using jquery for a while now but only thing i know about jquery is probably a dozen of functions that get my job done. but i want to understand how jquery evolved from simpl plain javascript i.e how
$("#xyz").val();
is converted to
document.getElementById('xyz').value;
i have searched for my answer on the web but most of the writers are happy to show how you can hook on to different DOM elements with jquery, selector details etc. but nothing can be found about how actually the transition was made. can anyone refer me to some tutorial where i can get my required material?
thanks
jQuery is not a compiler. jQuery does not get compiled into javascript.
.val is a method of an object. The jQuery object.
Specifically it is
function (value) {
if (!arguments.length) {
var elem = this[0];
if (elem) {
if (jQuery.nodeName(elem, "option")) {
// attributes.value is undefined in Blackberry 4.7 but
// uses .value. See #6932
var val = elem.attributes.value;
return !val || val.specified ? elem.value : elem.text;
}
// We need to handle select boxes special
if (jQuery.nodeName(elem, "select")) {
var index = elem.selectedIndex,
values = [],
options = elem.options,
one = elem.type === "select-one";
// Nothing was selected
if (index < 0) {
return null;
}
// Loop through all the selected options
for (var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++) {
var option = options[i];
// Don't return options that are disabled or in a disabled optgroup
if (option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) && (!option.parentNode.disabled || !jQuery.nodeName(option.parentNode, "optgroup"))) {
// Get the specific value for the option
value = jQuery(option).val();
// We don't need an array for one selects
if (one) {
return value;
}
// Multi-Selects return an array
values.push(value);
}
}
return values;
}
// Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
if (rradiocheck.test(elem.type) && !jQuery.support.checkOn) {
return elem.getAttribute("value") === null ? "on" : elem.value;
}
// Everything else, we just grab the value
return (elem.value || "").replace(rreturn, "");
}
return undefined;
}
var isFunction = jQuery.isFunction(value);
return this.each(function (i) {
var self = jQuery(this),
val = value;
if (this.nodeType !== 1) {
return;
}
if (isFunction) {
val = value.call(this, i, self.val());
}
// Treat null/undefined as ""; convert numbers to string
if (val == null) {
val = "";
} else if (typeof val === "number") {
val += "";
} else if (jQuery.isArray(val)) {
val = jQuery.map(val, function (value) {
return value == null ? "" : value + "";
});
}
if (jQuery.isArray(val) && rradiocheck.test(this.type)) {
this.checked = jQuery.inArray(self.val(), val) >= 0;
} else if (jQuery.nodeName(this, "select")) {
var values = jQuery.makeArray(val);
jQuery("option", this).each(function () {
this.selected = jQuery.inArray(jQuery(this).val(), values) >= 0;
});
if (!values.length) {
this.selectedIndex = -1;
}
} else {
this.value = val;
}
});
}
If we break the above wall down we can get
function (value) {
if (arguments.length === 0) {
return (this[0].value || "")
}
this.value = val;
return this;
}
Of course jQuery has a lot more code to deal with various edge cases and special things.
In essence jQuery takes a selector. finds the elements. Stores them internally then returns you an object.
This object has all kinds of methods that allow you to mutate the underlying dom objects stored internally. .val is one of them.
There are plenty of articles on how jQuery works (there are screencasts too).
jQuery, as you've noticed, is basically a bunch of methods operating on an array of elements. It is also intended to normalize browser differences under the hood.
Take the basic usage $("#xyz").val();
I can even tell you what jQuery is doing behind the scenes, but I don't think you really want to know. :)
var jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context );
},
// ...
jQuery.fn = jQuery.prototype = {
init: function( selector, context ) {
// ...
},
// ...
};
// Give the init function the jQuery prototype for later instantiation
jQuery.fn.init.prototype = jQuery.fn;
So basically $(selector) means newjQuery.fn.init(selector), it's just a shortcut for easier typing (and also to prevent the "bug" where fogetting new binds this to the global object, instead of the current instance).
Also, the so-called plug-ins added as jQuery.fn.ext are mapped to jQuery.fn.init.prototype as you can see in the last line, it's another shortcut. So when you call $(selector) everything that is added to jQuery.fn will also be on jQuery.fn.init.prototype and so the new instance will have those methods as $(selector).ext(...).
// as you use it today
jQuery.fn.plugin = function ( ... ) { ... }
$(selector).plugin( ... )
// as it would be without shortcuts
jQuery.fn.init.prototype.plugin = function ( ... ) { ... }
(new jQuery.fn.init(selector)).plugin( ... )

Is there any equivalent to dbug (a *really* pretty print for vars) for javascript?

I'm aware of console.log in firebug, and this thing called dbug (but not at all what I want). What I'm looking for is something that will give me a pretty print nested view into an object that looks like this for javascript:
(source: ospinto.com)
I'm also aware of this question, and am looking for something a little more tabular.
An attempt:
See a demo: http://jsbin.com/oxeki
The code:
var prettyPrint = (function(){
var htmlObj = function(obj){
if (Object.prototype.toString.call(obj) === '[object RegExp]') {
return obj.toSource ? obj.toSource() : '/' + obj.source + '/';
}
if (typeof obj === 'object') {
return prettyPrint(obj);
}
if (typeof obj === 'function') {
return document.createTextNode('function(){...}');
}
return obj.toString();
},
row = function(cells, type){
type = type || 'td';
var r = document.createElement('tr');
for (var i = 0, l = cells.length; i < l; i++) {
var td = document.createElement(type);
td.appendChild(typeof cells[i] === 'string' ? document.createTextNode(cells[i]) : cells[i]);
r.appendChild(td);
}
return r;
},
heading = function() {
var thead = document.createElement('thead');
thead.appendChild(row(['Name','Value'], 'th'));
return thead;
};
return function(obj) {
var tbl = document.createElement('table'),
tbody = document.createElement('tbody');
for (var i in obj) {
var objCellContent = obj[i] === obj ? document.createTextNode('CIRCULAR REFERENCE') : htmlObj(obj[i]);
tbody.appendChild( row([document.createTextNode(i), objCellContent]) );
}
tbl.appendChild(heading());
tbl.appendChild(tbody);
return tbl;
};
})();
I just saw this today, maybe this is what you're looking for?
I havn't run across such a debugger although it doesn't seem like this particular style would be too hard to write on your own. Just a basic recursive function passing in the current object and a table cell to start writing too, then just build as you go.
As for the circular reference comment above, this can be circumvented easily by keeping an array of objects that you have already processed. Before processing an object, check if it is already in the list. if so, denote that in the value field of your output as something like "circular reference to"...however you want to denote the object up the hierarchy.
prettyprint(object, processedObjects)
{
if (processedObjects.contains(object))
return 'circular refernece';
processedObjects.push(object);
create newTable;
for (var in object)
{
row = newTable.addRow();
row.cell1.value = var;
if (typeof object[var] is object)
row.cell2.value = prettyprint(object[var], processedObjects);
else if (typeof object[var] is function)
row.cell2.value = '[function]';
else
row.cell2.value = object[var].toString();
}
return newTable;
}
I think what you are looking for is this, http://www.netgrow.com.au/files/javascript_dump.cfm it's the javascript equivalent of coldfusion's dump tag

Categories

Resources