How can I set multiple attributes at once with JavaScript? Unfortunately, I'm not able to use a framework like jQuery on this project. Here is what I have now:
var elem = document.createElement("img");
elem.setAttribute("src", "http://example.com/something.jpeg");
elem.setAttribute("height", "100%");
elem.setAttribute("width", "100%");
You could make a helper function:
function setAttributes(el, attrs) {
for(var key in attrs) {
el.setAttribute(key, attrs[key]);
}
}
Call it like this:
setAttributes(elem, {"src": "http://example.com/something.jpeg", "height": "100%", ...});
You might be able to use Object.assign(...) to apply your properties to the created element. Although some "properties (elem.height etc.) are read-only, i.e. accessors with only a getter (undefined setter)."
Keep in mind that height and width attributes are defined in pixels, not percents. You'll have to use CSS to make it fluid.
var elem = document.createElement('img')
Object.assign(elem, {
className: 'my-image-class',
src: 'https://dummyimage.com/320x240/ccc/fff.jpg',
height: 120, // pixels
width: 160, // pixels
onclick: function () {
alert('Clicked!')
}
})
document.body.appendChild(elem)
// One-liner:
// document.body.appendChild(Object.assign(document.createElement(...), {...}))
.my-image-class {
height: 100%;
width: 100%;
border: solid 5px transparent;
box-sizing: border-box
}
.my-image-class:hover {
cursor: pointer;
border-color: red
}
body { margin:0 }
You could code an ES5.1 helper function:
function setAttributes(el, attrs) {
Object.keys(attrs).forEach(key => el.setAttribute(key, attrs[key]));
}
Call it like this:
setAttributes(elem, { src: 'http://example.com/something.jpeg', height: '100%' });
2023 Update
Don't use this as an extension to Element.prototype. In 2012, it was debatable practice. In 2023, the debate is settled: it's not the way to go about things. Manipulating the prototype of library-external classes has risks that are difficult or impossible to mitigate; this is an ugly tool. I tried to note that, but was apparently not emphatic enough.
However, you can read the internal approach of the method and write it as a function, it would work the same. I might use something like this:
const setAttributes = (el, attrs) =>
Object.keys(attrs)
.filter(key => el[key] !== undefined)
.forEach(key =>
typeof attrs[key] === 'object'
? Object.keys(attrs[key])
.forEach(innerKey => el[key][innerKey] = attrs[key][innerKey])
: el[key] = attrs[key]
);
http://jsfiddle.net/uL8tm603/46/
Original 2012 answer follows
If you wanted a framework-esq syntax (Note: IE 8+ support only), you could extend the Element prototype and add your own setAttributes function:
Element.prototype.setAttributes = function (attrs) {
for (var idx in attrs) {
if ((idx === 'styles' || idx === 'style') && typeof attrs[idx] === 'object') {
for (var prop in attrs[idx]){this.style[prop] = attrs[idx][prop];}
} else if (idx === 'html') {
this.innerHTML = attrs[idx];
} else {
this.setAttribute(idx, attrs[idx]);
}
}
};
This lets you use syntax like this:
var d = document.createElement('div');
d.setAttributes({
'id':'my_div',
'class':'my_class',
'styles':{
'backgroundColor':'blue',
'color':'red'
},
'html':'lol'
});
Try it: http://jsfiddle.net/ywrXX/1/
If you don't like extending a host object (some are opposed) or need to support IE7-, just use it as a function
Note that setAttribute will not work for style in IE, or event handlers (you shouldn't anyway). The code above handles style, but not events.
Documentation
Object prototypes on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/prototype
setAttribute on MDN - https://developer.mozilla.org/en-US/docs/DOM/element.setAttribute
You can create a function that takes a variable number of arguments:
function setAttributes(elem /* attribute, value pairs go here */) {
for (var i = 1; i < arguments.length; i+=2) {
elem.setAttribute(arguments[i], arguments[i+1]);
}
}
setAttributes(elem,
"src", "http://example.com/something.jpeg",
"height", "100%",
"width", "100%");
Or, you pass the attribute/value pairs in on an object:
function setAttributes(elem, obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
elem[prop] = obj[prop];
}
}
}
setAttributes(elem, {
src: "http://example.com/something.jpeg",
height: "100%",
width: "100%"
});
You could also make your own chainable object wrapper/method:
function $$(elem) {
return(new $$.init(elem));
}
$$.init = function(elem) {
if (typeof elem === "string") {
elem = document.getElementById(elem);
}
this.elem = elem;
}
$$.init.prototype = {
set: function(prop, value) {
this.elem[prop] = value;
return(this);
}
};
$$(elem).set("src", "http://example.com/something.jpeg").set("height", "100%").set("width", "100%");
Working example: http://jsfiddle.net/jfriend00/qncEz/
const setAttributes = (el, attrs) =>
Object.entries(attrs)
.forEach(args =>
el.setAttribute(...args))
Or create a function that creates an element including attributes from parameters
function elemCreate(elType){
var element = document.createElement(elType);
if (arguments.length>1){
var props = [].slice.call(arguments,1), key = props.shift();
while (key){
element.setAttribute(key,props.shift());
key = props.shift();
}
}
return element;
}
// usage
var img = elemCreate('img',
'width','100',
'height','100',
'src','http://example.com/something.jpeg');
FYI: height/width='100%' would not work using attributes. For a height/width of 100% you need the elements style.height/style.width
Try this
function setAttribs(elm, ob) {
//var r = [];
//var i = 0;
for (var z in ob) {
if (ob.hasOwnProperty(z)) {
try {
elm[z] = ob[z];
}
catch (er) {
elm.setAttribute(z, ob[z]);
}
}
}
return elm;
}
DEMO: HERE
you can simply add a method (setAttributes, with "s" at the end) to "Element" prototype like:
Element.prototype.setAttributes = function(obj){
for(var prop in obj) {
this.setAttribute(prop, obj[prop])
}
}
you can define it in one line:
Element.prototype.setAttributes = function(obj){ for(var prop in obj) this.setAttribute(prop, obj[prop]) }
and you can call it normally as you call the other methods. The attributes are given as an object:
elem.setAttributes({"src": "http://example.com/something.jpeg", "height": "100%", "width": "100%"})
you can add an if statement to throw an error if the given argument is not an object.
No function example:
let checkbox = document.createElement('input');
for (const [key, value] of Object.entries({
type: 'checkbox',
id: 'sys-surname',
class: 'switcher23',
value: 1,
name: 'surname'
})) {
checkbox.setAttribute(key, value);
}
let elem = document.createElement("img");
Object.entries({"src": "http://example.com/something.jpeg"),
"height": "100%",
"width": "100%"}).forEach(kv => elem.setAttribute(kv[0], kv[1]));
use this function to create and set attributes at the same time
function createNode(node, attributes){
const el = document.createElement(node);
for(let key in attributes){
el.setAttribute(key, attributes[key]);
}
return el;
}
use it like so
const input = createNode('input', {
name: 'test',
type: 'text',
placeholder: 'Test'
});
document.body.appendChild(input);
I guess it's best way to set attributes at once for any element in this class.
function SetAtt(elements, attributes) {
for (var element = 0; element < elements.length; element++) {
for (var attribute = 0; attribute < attributes.length; attribute += 2) {
elements[element].setAttribute(attributes[attribute], attributes[attribute + 1]);
}
}
}
var Class = document.getElementsByClassName("ClassName"); // class array list
var Data = ['att1', 'val1', 'att2', 'val2', 'att3', 'val3']; //attributes array list
SetAtt(Class, Data);
That's an easy way
let div = document.getElementsByTagName("div")[0];
let attr = ["class", "id", "title"];
let attrVlu = ["ahmed", "mohamed", "ashraf"];
for(let i = 0; i < 3; i++) {
div.setAttribute(attr[i], attrVlu[i]);
}
var elem = document.createElement("img");
function setAttributes(attributes) {
for (let key in attributes) {
elem.setAttribute(key, attributes[key]);
}
}
setAttributes({src: "http://example.com/something.jpeg",height: "100%",width: "100%",});
The most simple way is:
Create an array with objects into him, like:
array = [{obj1}, {obj2}, etc...]
next, you iterate on array to set the key's object like the
attribute and the value's object like the value of attribute:
example:
let arr = [{'id': 'myId'}, {'class': 'myClassname'}]
/iterate on array/
function setAt(array){
for (attr of array){
myElement.setAttribute(attr, array[attr])
}
}
later, you call the function passing your array like args:
setAt(arr)
THE EASIEST:
`
var elem = document.createElement("img");
var attrs = {
src: "http://example.com/something.jpeg",
height: "100%",
width: "100%"
}
Object.assign(elem, attrs);
`
Related
I was trying to make a function that gives you the selected CSS properties of an element those you want. But it's pretty laggy if used in console as of it needs to get and match all CSS properties.
function styleOf(elementUseSelectors, propertiesToCheck, tellInConsole) {
var element = elementUseSelectors;
var Arguments = propertiesToCheck;
var calculatedProperties = [];
var matchedProperties = [];
if (tellInConsole !== undefined && tellInConsole == true) {
console.warn("Running styleOf() Please Don't Do Other Calculations This Function Disables Console.")
}
for (var i = 0; i < Object.keys(getComputedStyle(element)).length; i++) {
var value = getComputedStyle(element).getPropertyValue(Object.entries(getComputedStyle(element))[i][0].replace(/([A-Z])/g, ' $1').trim().replaceAll(" ", "-").toLowerCase());
if (value !== "") {
calculatedProperties.push(Object.entries(getComputedStyle(element))[i][0].replace(/([A-Z])/g, ' $1').trim().replaceAll(" ", "-").toLowerCase() + ": " + value);
}
}
for (var i = 0; i < calculatedProperties.length; i++) {
for (var a = 0; a < Arguments.length; a++) {
if (calculatedProperties[i].includes(Arguments[a])) {
window.splitted = calculatedProperties[i].split("");
window.joinThis = [];
for (var k = 0; k < splitted.indexOf(":"); k++) {
joinThis.push(splitted[k]);
};
if (joinThis.join("") == Arguments[a]) {
matchedProperties.push(calculatedProperties[i]);
}
}
}
}
if (tellInConsole !== undefined && tellInConsole == true) {
console.warn("StyleOf() Calculations Completed You Can Now Use Console.")
}
return matchedProperties
}
The TreeWalker object is designed to quickly parse DOM nodes in a document. If you expand on the example given above in the MDN Web Docs you can output the computed CSS properties for a given node.
The first property of the method is the node you want to traverse – in this case it's document.body:
var treeWalker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_ELEMENT,
{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT; } },
false
);
var nodeList = [];
var currentNode = treeWalker.currentNode;
while(currentNode) {
nodeList.push(currentNode);
const style = getComputedStyle(currentNode)
console.log(style)
currentNode = treeWalker.nextNode();
console.log("moving to next node...");
}
Welp #kaiido answered the question.
function styleOf(element, properties) {
const computed = getComputedStyle(element);
return properties.map( key => key + ": " + computed[ key ] )};
var style = styleOf(document.getElementsByTagName("body")[0], ["height", "width", "background-color", "font-size", "color", "font-family"]);
console.log(style);
I am trying to append content to a parent element using a loop inside a function.
I want to append several divs to an element, but (obviously) want the flexibility to change things such as class name, text, etc.
Here is my code:
var head = document.getElementById('head');
var someText = "Hello, World";
var someAttributes = [['class', 'blue'], ['id', 'footer'], ['name', 'bunk']];
function createEl(tag, parent) {
var newElement = document.createElement(tag);
return parent.appendChild(newElement);
}
function addText(text, parent) {
return parent.textContent = text;
}
function addAttribute(attributes, parent) {
for(var i = 0; i < attributes.length; i++) {
parent.setAttribute(attributes[i][0], attributes[i][1]);
}
}
function newEl(parent, element, attr, text) {
var el = createEl(element, parent);
addText(text, el);
addAttribute(attr, el);
return parent;
}
var derp = newEl(head, 'div', someAttributes, someText);
function loop(num, content) {
for(var i = 0; i < num; i++) {
content;
console.log('derp');
}
}
loop(3, derp);
I can get it working if I change it to the following:
function loop(num, a, b, c, d) {
for(var i = 0; i < num; i++) {
content newEl(a, b, c, d);
console.log('derp');
}
}
loop(3, head, 'div', someAttributes, someText);
Why it doesn't work with loop(3, derp)
derp is useless variable which holds head (the return value of newEl), make it function and call inside loopo
var derp = function(){
return newEl(head, 'div', someAttributes, someText);
};
function loop(num, content) {
for(var i = 0; i < num; i++) {
content(); // <== call function derp here
console.log('derp');
}
}
loop(3, derp);
Create one function and loop everything within that function. In order to keep track of each element, push them into an array. Remember, ids must be unique, so addAttribute() will invalidate your HTML because each element will have the same id. Btw, try to avoid functions within loops, it can get messy.
SNIPPET
var base = document.createElement('main');
document.body.appendChild(base);
var tag = "div";
var str = " reporting for duty, sir!";
var att = [['class', 'infantry'], ['name', 'trooper']];
var cnt = 0;
var qty = 3;
var ico = 'https://cdn2.iconfinder.com/data/icons/starwars/icons/128/clone-4.png';
function cloneLab(tag, str, att, qty) {
var unit = [];
for(var i = 0; i < qty; i++) {
var trooper = document.createElement(tag);
unit.push(trooper);
cnt++;
unit[i].id = 'trooper'+cnt;
for(var j = 0; j < att.length; j++) {
trooper.setAttribute(att[j][0], att[j][1]);
}
trooper.textContent = unit[i].id + str;
trooper.style.backgroundImage = "url("+ico+")";
base.appendChild(unit[i]);
}
return unit;
}
cloneLab(tag, str, att, qty);
main { border: 5px inset grey; }
.infantry { border: 1px solid blue; background-repeat: no-repeat; background-position: center; background-size: contain; }
You could use Object.create(derp); to build new objects that inherit from derp
var head = document.getElementById('head');
var someText = "Hello, World";
var someAttributes = [
['class', 'blue'],
['id', 'footer'],
['name', 'bunk']
];
function createEl(tag, parent) {
var newElement = document.createElement(tag);
return parent.appendChild(newElement);
}
function addText(text, parent) {
return parent.textContent = text;
}
function addAttribute(attributes, parent) {
for (var i = 0; i < attributes.length; i++) {
parent.setAttribute(attributes[i][0], attributes[i][1]);
}
}
function newEl(parent, element, attr, text) {
var el = createEl(element, parent);
addText(text, el);
addAttribute(attr, el);
return parent;
}
var derp = newEl(head, 'div', someAttributes, someText);
function loop(num, content) {
for (var i = 0; i < num; i++) {
newEl(head, 'div', someAttributes, someText);
Object.create(derp);
}
}
loop(3, derp);
.blue {
color: blue;
}
<div id="head" />
There are few issues with the code here.
Firstly you there is no element with the id of 'head' to get as parent. So the js fails right away.
Even if you have an element with the name of 'head', you need to wait till the document loaded.
Either you can use jQuery document.ready function or document.addEventListener("DOMContentLoaded", function(event) { }); if you gonna use pure js. You can copy your code in side these above mentioned functions.
If you follow these steps your code will work perfectly.
PS: Please note that document.addEventListener("DOMContentLoaded", function(event) { }); may not work with IE.
HOPE THIS WILL HELP YOU.
I am getting familiar with the prototype world of JavaScript and this keyword. I am new to Web-world. Today when I started playing with prototype I saw some strange behavior but I am not able to get why this is happening. I've created a constructor Group as following:
// Code goes here
function Group(config) {
this.config = config;
this.getId = function() {
return this.config.id;
};
this.setId = function(id) {
this.config.id = id;
};
}
I use it in one MyGroup constructor like this:
function MyGroup(config) {
var myAttrs = ['id', 'name'];
this.g = new Group(config);
addGetterSetter(MyGroup, this.g, myAttrs)
}
addGetterSetter is the function I wrote to add getter and setter dynamically to the attributes of MyGroup.
var GET = 'get',
SET = 'set';
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function addGetterSetter(constructor, target, attrs) {
function addGetter(constructor, target, attr) {
var method = GET + capitalize(attr);
constructor.prototype[method] = function() {
return target[method]();
};
}
function addSetter(constructor, target, attr) {
var method = SET + capitalize(attr);
constructor.prototype[method] = function(value) {
return target[method](value);
};
}
for (var index = 0; index < attrs.length; index++) {
addGetter(constructor, target, attrs[index]);
addSetter(constructor, target, attrs[index]);
}
}
Now when I use MyGroup,Group like this:
var items = [{
id: 123,
name: 'Abc'
}, {
id: 131,
name: 'Bca'
}, {
id: 22,
name: 'bc'
}];
var groups = [];
items.forEach(function(item) {
var g = new MyGroup(item);
groups.push(g);
});
groups.forEach(function(g) {
console.log(g.getId()); //don't know why this logs 22 three times instead of all ids
});
In group.forEach I don't know why the id of the last item is getting logged. I am not able to understand what is going wrong. And how will I be able to get of the group for which g.getId() is invoked. Here is the plunkr
It's because you're adding methods to prototype and you overwrite in the loop each time the previous function so the function hold reference to last object when forEach loop finishes. What you need is to add function to this object:
function MyGroup(config) {
var myAttrs = ['id', 'name'];
this.g = new Group(config);
addGetterSetter(this, this.g, myAttrs)
}
function addGetterSetter(object, target, attrs) {
function addGetter(object, target, attr) {
var method = GET + capitalize(attr);
object[method] = function() {
return target[method]();
};
}
function addSetter(object, target, attr) {
var method = SET + capitalize(attr);
object[method] = function(value) {
return target[method](value);
};
}
for (var index = 0; index < attrs.length; index++) {
addGetter(object, target, attrs[index]);
addSetter(object, target, attrs[index]);
}
}
JSFIDDLE
I have a JavaScript function that I want to fire once the user enters text inside an input element. Currently I can only see the function firing if I console.log it. How do I get it to fire using keyup method?
The relevant code is below.
var $ = function (selector) {
var elements = [],
i,
len,
cur_col,
element,
par,
fns;
if(selector.indexOf('#') > 0) {
selector = selector.split('#');
selector = '#' + selector[selector.length -1];
}
selector = selector.split(' ');
fns = {
id: function (sel) {
return document.getElementById(sel);
},
get : function(c_or_e, sel, par) {
var i = 0, len, arr = [], get_what = (c_or_e === 'class') ? "getElementsByClassName" : "getElementsByTagName";
if (par.length) {
while(par[I]) {
var temp = par[i++][get_what](sel);
Array.prototype.push.apply(arr, Array.prototype.slice.call(temp));
}
} else {
arr = par[get_what](sel);
}
return (arr.length === 1)? arr[0] : arr;
}
};
len = selector.length;
curr_col = document;
for ( i = 0; i < len; i++) {
element = selector[i];
par = curr_col;
if( element.indexOf('#') === 0) {
curr_col = fns.id(element.split('#'[1]));
} else if (element.indexOf('.') > -1) {
element = element.split('.');
if (element[0]) {
par = fns.get('elements', element[0], par);
for ( i =0; par[i]; i++) {
if(par[i].className.indexOf(element[1]> -1)) {
elements.push(par[i]);
}
}
curr_col = elements;
} else {
curr_col = fns.get('class', element[1], par);
}
} else {
curr_col = fns.get('elements', element, par);
}
}
return elements;
};
You need to bind your method to the keyup event on the page.
You could try
document.addEventListener('keyup', $)
Or assuming you have the input element as element you could do
element.addEventListener('keyup', $)
Your function will be passed the event which you could use to investigate the state of the element if you needed that information to trigger or not trigger things in the function.
Here's a quick sample where the function that get's run on keypress is changeColor.
var COLORS = ['red', 'blue','yellow', 'black']
var NCOLORS = COLORS.length;
function changeColor(ev) {
var div = document.getElementById('colored');
var colorIdx = parseInt(Math.random() * NCOLORS);
console.log(colorIdx);
var newColor = COLORS[colorIdx];
div.style.color = newColor
console.log("New color ", newColor)
}
document.body.addEventListener('keyup', changeColor)
Though I'm not using the event (ev), I like to show, in the code, that I expect that variable to be available.
See it in action here - http://codepen.io/bunnymatic/pen/yyLGXg
As a sidenote, you might be careful about calling your function $. Several frameworks (like jQuery) use that symbol and you may run into conflicts where you're overriding the global variable $ or where the framework overrides your version if it.
Is it possible to simply add event listeners to certain elements to detect if their height or width have been modified? I'd like do this without using something intensive like:
$(window).resize(function() { ... });
Ideally, I'd like to bind to specific elements:
$("#primaryContent p").resize(function() { ... });
It seems like using a resize handler on the window is the only solution, but this feels like overkill. It also doesn't account for situations where an element's dimensions are modified programatically.
I just came up with a purely event-based way to detect element resize for any element that can contain children, I've pasted the code from the solution below.
See also the original blog post, which has some historical details. Previous versions of this answer were based on a previous version of the blog post.
The following is the JavaScript you’ll need to enable resize event listening.
(function(){
var attachEvent = document.attachEvent;
var isIE = navigator.userAgent.match(/Trident/);
var requestFrame = (function(){
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
function(fn){ return window.setTimeout(fn, 20); };
return function(fn){ return raf(fn); };
})();
var cancelFrame = (function(){
var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
window.clearTimeout;
return function(id){ return cancel(id); };
})();
function resizeListener(e){
var win = e.target || e.srcElement;
if (win.__resizeRAF__) cancelFrame(win.__resizeRAF__);
win.__resizeRAF__ = requestFrame(function(){
var trigger = win.__resizeTrigger__;
trigger.__resizeListeners__.forEach(function(fn){
fn.call(trigger, e);
});
});
}
function objectLoad(e){
this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__;
this.contentDocument.defaultView.addEventListener('resize', resizeListener);
}
window.addResizeListener = function(element, fn){
if (!element.__resizeListeners__) {
element.__resizeListeners__ = [];
if (attachEvent) {
element.__resizeTrigger__ = element;
element.attachEvent('onresize', resizeListener);
}
else {
if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
var obj = element.__resizeTrigger__ = document.createElement('object');
obj.setAttribute('style', 'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1;');
obj.__resizeElement__ = element;
obj.onload = objectLoad;
obj.type = 'text/html';
if (isIE) element.appendChild(obj);
obj.data = 'about:blank';
if (!isIE) element.appendChild(obj);
}
}
element.__resizeListeners__.push(fn);
};
window.removeResizeListener = function(element, fn){
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
if (attachEvent) element.detachEvent('onresize', resizeListener);
else {
element.__resizeTrigger__.contentDocument.defaultView.removeEventListener('resize', resizeListener);
element.__resizeTrigger__ = !element.removeChild(element.__resizeTrigger__);
}
}
}
})();
Usage
Here’s a pseudo code usage of this solution:
var myElement = document.getElementById('my_element'),
myResizeFn = function(){
/* do something on resize */
};
addResizeListener(myElement, myResizeFn);
removeResizeListener(myElement, myResizeFn);
Demo
http://www.backalleycoder.com/resize-demo.html
Here is a jQuery plugin with watch and unwatch methods that can watch particular properties of an element. It is invoked as a method of a jQuery object. It uses built-in functionality in browsers that return events when the DOM changes, and uses setTimeout() for browsers that do not support these events.
The general syntax of the watch function is below:
$("selector here").watch(props, func, interval, id);
props is a comma-separated string of the properties you wish to
watch (such as "width,height").
func is a callback function, passed the parameters watchData, index, where watchData refers to an object of the form { id: itId, props: [], func: func, vals: [] }, and index is the index of the changed property. this refers to the changed element.
interval is the interval, in milliseconds, for setInterval() in browsers that do not support property watching in the DOM.
id is an optional id that identifies this watcher, and is used to remove a particular watcher from a jQuery object.
The general syntax of the unwatch function is below:
$("selector here").unwatch(id);
id is an optional id that identifies this watcher to be removed. If id is not specified, all watchers from the object will be removed.
For those who are curious, the code of the plugin is reproduced below:
$.fn.watch = function(props, func, interval, id) {
/// <summary>
/// Allows you to monitor changes in a specific
/// CSS property of an element by polling the value.
/// when the value changes a function is called.
/// The function called is called in the context
/// of the selected element (ie. this)
/// </summary>
/// <param name="prop" type="String">CSS Property to watch. If not specified (null) code is called on interval</param>
/// <param name="func" type="Function">
/// Function called when the value has changed.
/// </param>
/// <param name="func" type="Function">
/// optional id that identifies this watch instance. Use if
/// if you have multiple properties you're watching.
/// </param>
/// <param name="id" type="String">A unique ID that identifies this watch instance on this element</param>
/// <returns type="jQuery" />
if (!interval)
interval = 200;
if (!id)
id = "_watcher";
return this.each(function() {
var _t = this;
var el = $(this);
var fnc = function() { __watcher.call(_t, id) };
var itId = null;
if (typeof (this.onpropertychange) == "object")
el.bind("propertychange." + id, fnc);
else if ($.browser.mozilla)
el.bind("DOMAttrModified." + id, fnc);
else
itId = setInterval(fnc, interval);
var data = { id: itId,
props: props.split(","),
func: func,
vals: []
};
$.each(data.props, function(i) { data.vals[i] = el.css(data.props[i]); });
el.data(id, data);
});
function __watcher(id) {
var el = $(this);
var w = el.data(id);
var changed = false;
var i = 0;
for (i; i < w.props.length; i++) {
var newVal = el.css(w.props[i]);
if (w.vals[i] != newVal) {
w.vals[i] = newVal;
changed = true;
break;
}
}
if (changed && w.func) {
var _t = this;
w.func.call(_t, w, i)
}
}
}
$.fn.unwatch = function(id) {
this.each(function() {
var w = $(this).data(id);
var el = $(this);
el.removeData();
if (typeof (this.onpropertychange) == "object")
el.unbind("propertychange." + id, fnc);
else if ($.browser.mozilla)
el.unbind("DOMAttrModified." + id, fnc);
else
clearInterval(w.id);
});
return this;
}
Yes it is possible. You will have to track all of the elements on load and store it. You can try out the demo here. In it, you don't have to use any libraries, but I used jQuery just to be faster.
First thing first - Store their initial size
You can do that by using this method:
var state = []; //Create an public (not necessary) array to store sizes.
$(window).load(function() {
$("*").each(function() {
var arr = [];
arr[0] = this
arr[1] = this.offsetWidth;
arr[2] = this.offsetHeight;
state[state.length] = arr; //Store all elements' initial size
});
});
Again, I used jQuery just to be fast.
Second - Check!
Of course you will need to check if it has been changed:
function checksize(ele) {
for (var i = 0; i < state.length; i++) { //Search through your "database"
if (state[i][0] == ele) {
if (state[i][1] == ele.offsetWidth && state[i][2] == ele.offsetHeight) {
return false
} else {
return true
}
}
}
}
Simply it will return false if it has not been change, true if it has been change.
Hope this helps you out!
Demo: http://jsfiddle.net/DerekL/6Evk6/