extend properties in javascript - javascript

i have this code in javascript:
var object = {
get: function(id){
sel = document.getElementById(id);
sel.orig = {};
...
return object.extend(sel, object);
}
extend: function(el, opt){
for(var name in opt) el[name] = opt[name];
return el;
}
}
and in another js i have
var Multi = {
set: function(){
if(!this.orig["height"]) this.orig["height"] = this.offsetHeight;
...
return this;
}
}
object.extend(object,Multi);
and i call it like this:
object.get('myId').set();
but when in the "set" method, the property this.orig["height"] is always undefined, so it always will change the value and that's not the idea, i need to capture it the first time because im trying to make an Fx framework and i that's for the slideUp function, i need to keep the original height, so i can go back again.
Any ideas please? thank you

Now, in contrast to some people's answers comments being completely non constructive I assume your true question regards this little ditty:
extend: function(el, opt){
for(var name in opt) el[name] = opt[name];
return el;
}
and why it returns undefined? It does'nt... your problem lies elsewhere, because this works:
var object = {
get: function(id) {
el = document.getElementById(id);
el.orig = {};
return object.extend(el,object);
},
extend: function( el, opt ) {
for(var name in opt) el[name] = opt[name];
return el;
}
}
var Multi = {
set: function() {
if(!this.orig['height']) this.orig['height'] = this.offsetHeight;
console.log( this.orig['height'] ); // if the value of offsetHeight itself is not undefined, it is what is returned.
}
}
object.extend(object,Multi);
object.get('myId').set();

hey, thanks for the comments and overall for the answer Quickredfox!! i found the problem, in this part:
get: function(id) {
el = document.getElementById(id);
el.orig = {};
return object.extend(el,object);
},
i just changed to this:
get: function(id) {
el = document.getElementById(id);
if(!el.orig) el.orig = {};
return object.extend(el,object);
},
and voila!! thank you very much for your answer!

Related

How to return an array from constructor and successfully chain the object in Javascript

I've been going through the jQuery code and I have seen a few links that have this question. I am asking it again because I did not really understand any of them so please do not mark this question as duplicate. I've gone through the following stackoverflow links:
How can jQuery return an array and still have it to be a jQuery object
How does jQuery chaining work
How does jQuery return an array of the selected objects
Gone through all of those links and I do not get how it works. All I ask is a very simple example of returning an array from a constructor object and still chaining it. I have tried the following code:
(function(window, document, undefined)
{
var lhd = function(selector)
{
return new Lhd(selector);
}
function Lhd(selector)
{
var elem = document.querySelectorAll(selector),
elems = {};
return this.makeArray(elems, elem);
}
Lhd.prototype = {
makeArray: function(arr, result)
{
var ret = result || [];
Array.prototype.push.apply(ret, arr);
return ret;
},
click: function()
{
console.log('click');
return this;
}
};
window.lhd = lhd;
})(window, document);
I'm able to return an array but unable to chain it.
I'm able to return an array
You must not return an array, you must make the new instance (this) become array-like.
function lhd(selector) {
return new Lhd(selector);
}
function Lhd(selector) {
var elems = document.querySelectorAll(selector);
this.length = 0; // initialise a length
Array.prototype.push.apply(this, elems); // push onto the instance
// don't `return` anything - it's a constructor
}
Lhd.prototype.click = function() {
console.log('click');
return this;
};
You can use it now like lhd('a').click().click().

Linking property of a custom element to it's attribute

Question & Demo
I've recently started to work with custom elements.
As you know, a HTMLElement has both a markup inside the document, and a JavaScript object. So, with my custom element, I've tried to link the JavaScript object properties with the element's attributes.
So, if any of those is updated, the other would be updated as well. But this isn't happening and I swear I've tried everything, maybe is something stupid I'm missing but for me, how this code is behaving is a freaking mistery.
After reading the code explanation below and seen the demo, you should be able to understand my question:
Why are the custom element attributes updating correctly, but not it's properties?
I've setup a JSFiddle to illustrate my problem, and I will be going over how the code is supposed to work in this post.
HTML
<e-button color="red" width="250px">RED BUTTON</e-button>
Well it rarely gets any simpler than that. I create a custom object called "e-button", with color=red and width=250px.
JavaScript
var eButtonProto = Object.create(HTMLElement.prototype);
eButtonProto.createdCallback = function() {
this.__htmlToJsProp(); //Gets all the HTML attributes and makes them accessible via JS.
this.__processAttr(); //Makes decision upon predefined attributes.
}
eButtonProto.__htmlToJsProp = function() {
var attr = this.attributes;
for (var i = 0; i < attr.length; i++) {
var current = attr[i];
var name = current.name;
var value = current.value;
this[name] = value;
Object.defineProperty(this, name, {
get: function() {
return this.getAttribute(name);
},
set: function(val) {
this.setAttribute(name, val);
}
});
}
}
eButtonProto.attributeChangedCallback = function(name, oldVal, val) {
this[name] = val;
this.__processAttr();
}
eButtonProto.__processAttr = function() {
var color = this.color || this.defaults.color;
this.style.backgroundColor = color;
}
eButtonProto.defaults = {
color: "whitesmoke"
}
var eButton = document.registerElement("e-button", {
prototype: eButtonProto
});
window.onload = function() {
redButton = document.querySelector("e-button[color=red]");
console.log("button ATTRIBUTES", redButton.getAttribute("color"), redButton.getAttribute("width"));
console.log("button PROPERTIES", redButton.color, redButton.width);
} < /script>
The really important code snippets here are these, which essentialy should make my idea work, first, the __htmlToJsProp() function:
eButtonProto.__htmlToJsProp = function() {
var attr = this.attributes; //Gets the element's attributes.
for (var i = 0; i < attr.length; i++) {
var current = attr[i]; //Element attribute name,value pair.
var name = current.name; //Attribute name.
var value = current.value; //Attribute value.
Object.defineProperty(this, name, { //Defines the element property from the attribute name, for simplicity I will be using the color attribute as my example.
get: function() {
return this.getAttribute(name); //When accessing element.color you should get element.getAttribute("color")
},
set: function(val) {
this.setAttribute(name, val); //When setting element.color = "red" you should also be doing element.setAttribute("color","red");
}
});
this[name] = value; //Sets element.color = "red"
}
}
and then the attributeChangedCallback function:
eButtonProto.attributeChangedCallback = function(name, oldVal, val) {
this[name] = val; //This would be the other way around, if the attribute is updated via setAttribute, or the browser console, the property is updated (works).
this.__processAttr(); //You can ignore this
}
Conclusions
You see after testing A LOT I found that if you place yourself in the for loop and output the property value, it will give you element.color = "red" and element.width = "250px";
But if you test it outside the for loop, it gives you element.color = "250px" and element.width = "250px" for the properties but the attributes update properly, that is element.getAttribute("color") = "red" and element.getAttribute("width") = "250px".
If you made it this far, well thanks, hopefully you can find a way out of this problem, which I really don't seem to be able to solve, happy coding :)
Your issue seems to be within the for loop, the getters and setters are called later, so the value of i isn't what you think it is, the loop completes and sets i to the latest iterated value.
You'll solve it with a closure
eButtonProto.__htmlToJsProp = function () {
var attr = this.attributes;
for (var i = 0; i < attr.length; i++) {
(function(current, self) {
var name = current.name;
var value = current.value;
Object.defineProperty(self, name, {
get: function () {
return this.getAttribute(name);
},
set: function (val) {
this.setAttribute(name, val);
}
});
self[name] = value;
})(attr[i], this);
}
}
FIDDLE

How to call a method(function) of a plugin from outside of that plugin

I know this is an old question in stackoverflow. But for me it is new, I have searched for a solution but I didn't got a solution which I can understand. I have a plugin, in that I have some functions. Now I want to access one of the function when an event changes on select options. But my problem is I'm not able access the function from outside of the plugin. However I'm new to plugin development.
here is my plugin :
(function($, window, document, undefined) {
var Spec = {
init: function(options, ele)
{
var self = this;
self.elem = ele;
self.$elem = $(ele);
self.findPro = (typeof options === 'string') ? self.findPro = options : self.findPro = options.findPro;
self.options = $.extend({}, $.fn.specpro.options, options);
if (self.options.findPro === 'latest') {
self.latestPro();
}
},
latestPro:function(){
var results=['x','y','z','zx'];
var pinSelector = $('<select/>').addClass('form-control chzn-select chzn-rtl').attr({'data-placeholder': 'Add pins to filter',
'multiple': true, 'id': 'pinSelector'}).append($('<option/>').attr('value', ''));
$.each(results,function(i,item){
pinSelector.append($('<option/>').attr('value',item).text(item));
});
pinSelectorCt = $('<div/>').addClass('col-lg-12').append(pinSelector);
$('#lp').append(pinSelectorCt);
$(".chzn-select").chosen();
},
filter:function(filFor){
this.html('zzz');
}
};
$.fn.specpro = function(options) {
return this.each(function() {
var spec = Object.create(Spec);
spec.init(options, this);
});
};
$.fn.specpro.options = {
findPro: 'latest'
};
})(jQuery, window, document);
And what I tried is :
$(function(){
var mn=$('#lp').specpro({findPro:'latest'});
$('.chzn-select').chosen().change().mn.filter('latest');
});
Can anyone tell me. How can I call the function filter from outside of the plugin.
Live Fiddle
One easy solution is to expose the plugin instance itself like
$.fn.specpro = function (options) {
return this.each(function () {
var spec = Object.create(Spec);
spec.init(options, this);
$(this).data('specpro', spec)
});
};
then
var specpro = $('#lp').data('specpro');
specpro.filter();//call which ever method you want
Demo: Fiddle

IE select not appending options

I created a currency converter object and it works great except in IE. None of options get appended to the select element. I have been trying to find a solution for hours but can't figure out what is going on. I am new to javascript so I may be doing something completely wrong just not sure what. It seems like the render method is not getting called from within fetch. Thanks
var CurrencyConverter = {
// Initialize Currency Converter
// total: jQuery wrapped object that contains the price to convert
// select: jQuery wrapped select element to render the options tag in
init: function (total, select) {
var that = this;
this.total = total;
this.base_price = accounting.unformat(this.total.text());
this.select = select;
this.fetch();
select.change(function () {
var converted = '',
formated = '';
fx.settings = { from: fx.base, to: this.value };
converted = fx.convert(that.base_price);
formated = accounting.formatMoney(converted, { symbol: this.value, format: "%s %v", precision: "0" });
$(that.total).text(formated);
});
},
// Render Currency Options
render: function () {
var that = this,
accumulator = [],
frag = '';
for (var propertyName in fx.rates) {
accumulator.push(propertyName);
}
$.each(accumulator, function ( i, val ) {
var the_price = $(document.createElement('option')).text(val);
if (val == fx.base) {
the_price.attr('selected', 'true');
}
// TODO: not optimal to run append through each iteration
that.select.append(the_price);
});
},
// Fetch & set conversion rates
fetch: function () {
var that = this;
// Load exchange rates data via the cross-domain/AJAX proxy:
$.getJSON(
'http://openexchangerates.org/latest.json',
function(data) {
fx.rates = data.rates;
fx.base = data.base;
that.render();
}
);
}
};
if ($('#currency-select')) {
CurrencyConverter.init($('#price'), $('#currency-select'));
}
Your problem is scope.
init: function (total, select) {
var that = this; // Ok, `that` is `init`...
this.total = total;
this.base_price = accounting.unformat(this.total.text());
this.select = select; // So `init.select = select`...
.
.
.
render : function () {
var that = this, // Ok, `that` is `render`
accumulator = [],
frag = '';
.
.
.
that.select.append(the_price); // ?????
The easiest way to solve this, is to create a constructor function instead of a literal object so you can pass $select as an object to which you have access within any method.
var CurrencyConverter = function($select){
this.init = function(){ ... }
this.render = function() { $select.append('...'); }
.
.
.
};
var currency = new CurrencyConverter($('select'));
Ye, i've ran too in this. Don't know if it's the right way to solve this but it works, implying that.select is a jQuery result:
that.select.get(0).add(the_price.get(0))
Tutorial about working

jQuery function not returning

(function($){
$.a.b = {
title: "ABC",
init: function (id) {
/* do something here */
return id+'a';
}
};
})(jQuery);
When I try to call $.a.b.init('t'); it does not work, I mean it does not return as expected. Any suggestions?
The problem is not that $.a.b.init('t') is not working. Problem is that it returns the code of the whole function instead of returning say a string.
Thank you for your time.
try
$.a = [];
$.a.b = { ... }
or even better:
$.a = {b: {
title: "",
init: ...
}};
When using $.a.b a is undefined, so you cannot add to it.
Since $.a is not yet defined you cannot set the b property. First you'll need to create $.a. Alternatively, use a namespacing helper:
$.namespace = function(ns) {
var cur = $, split = ns.split('.');
while (split[0]) {
cur = cur[split.shift()] = {};
}
return cur;
};
$.namespace('a').b = { ... };
It can also be used with deeper namespaces:
$.namespace('a.b.c.d.e.f').g = 123;
$.a.b.c.d.e.f.g; // => 123

Categories

Resources