how would i implement something like jquerys .data() in pure javascript? - javascript

A project I am working on for works wants a pure JavaScript version of the .data() implementation of jQuery.
I wanted to replicate this.
I did a search and Where is jQuery.data() stored? shows where in jQuery it is stored.
I was hoping that i could just attach a datasegment to an HTML element for accessing later.
Since jQuery is Javascript, I can look there, but it makes use of the jQuery objects, which is what I am trying to abstract. I figured there was some sort of way to associate a hash table like dataset with JavaScript and attach it to an object.

http://jsfiddle.net/npXQx/
shows you can create a .data in the object and then it is preserved. You can access it twice, and the data is there.
This example shows a simple string assignment and a function and it being called multiple times.
var item = document.getElementById("hi");
console.log(item);
item.data = {getType: function(){return this.TYPE},TYPE:"winner"};
var out = item.data.getType();
console.log("out", out);
var two = document.getElementById("hi")
console.log("should say 'winner': ", two.data.getType());

Related

jQuery version of simple javascript doesnt work

I have this code in javascript
var greet;
greet = function() {
var textoNombre;
textoNombre = document.getElementById("textoNombre");
return alert(textoNombre.value);
};
what is working on the HTML document. But if I change document.getElementById("textoNombre") by the jQuery version $("#textoNombre") it just dont work. The alert says "undefined".
I have the jQuery script linked on the head of the HTML before to my custom js file.
This is a very basic question but I tried different things and no one work, can you help me please? Thank you in advance.
That's because jQuery objects don't have a value property, the equivelant is $('#someId').val().
To get the underlying DOM object, you can use $('#someId')[0]. This is because jQuery objects are actually like arrays, and their elements are the DOM objects themselves. That means $('#someId')[0].value would work as you'd expect.
jQuery objects are not DOM objects and don't share all their properties.
To get the current value of a form control, you would use the .val() method, not the .value property.

jQuery single line code optmization for getting and setting for the same input element

I'm using PHPStorm and have the following js code
$('#id'.val($('#id'.attr('default'));
The idea is to reset the value of a input field to it's default which is set in default attribute of the input element.
Now the IDE is suggesting me to avoid duplicate selectors.
Though it is working I'm interested in finding out what is the best way to optimize this code line?
Not exactly what you asked for but more future proof using data and not an attribute. You could even store complex data or other information in there as well like "originalvalue" or "lastchangedvalue" etc.
Storing in an attribute is fine however I prefer to store things like this in the data of the element like:
<myelementtag id="myid" data-defaultvalue="defaultvalue" />
You then access it like:
$('#myid').data("defaultvalue");
For example:
var myElement = $('#myid');
myElement.value = myElement.data('defaultvalue');
Want to reset the default?
var mynewdefault = "mynewvalue";
myElement.data('defaultvalue', mynewdefault);
Since you asked only one selector and one line code, please use like this as stated in jQuery documentation (middle section):
$("#id").val(function(index,value) {
return $(this).attr('default');
});
or if you want to avoid $(this):
$("#id").val(function (index, value) {
return this.getAttribute('default');
});
JSFiddle
And yes, as other members have pointed out, it would be better if you use data attribute (data-defaultValue) instead.
This is a more compact solution:
var id = $('#id');
id.val(id.attr('default'));
You really don't need to use $(...) every time.
Store your jQuery element in a variable:
var $id = $('#id');
$id.val($id.attr('default'));

Can JQuery and Javascript be mixed together?

I am wondering if I could use query and javascript together so I could select an element by class with the javascript and then use javascript to work on that element. Sorry if that didn't make sense. Here is an example:
$('.nav_flag').src = "images/flags/"+userCountryLower+".gif";
Would that work, if not how do I get an element by class using regular javascript. Thanks!
EDIT:I know JQUERY is JavaScript but I was wondering if I could mix jquery selectors and javascript 'controller'-for a loss of a better word
To answer your question as asked, there are several ways to take a jQuery object, i.e., what is returned by $('some selector'), and get a reference to the underlying DOM element(s).
You can access the individual DOM elements like array elements:
// update the src of the first matching element:
$(".nav_flag")[0].src = "images/flags/"+userCountryLower+".gif";
// if you're going to access more than one you should cache the jQuery object in
// a variable, not keep selecting the same thing via the $() function:
var navFlgEls = $(".nav_flag");
for (var i = 0; i < navFlgEls.length; i++) { ... }
But you wouldn't manually loop through the elements when you can use jQuery's .each() method, noting that within the callback function you provide this will be set to the current DOM element:
$(".nav_flag").each(function() {
this.src = "images/flags/"+userCountryLower+".gif";
});
However, jQuery provides a way to set attributes with one line of code:
$(".nav_flag").attr("src", "images/flags/"+userCountryLower+".gif");
To answer the second part of your question, doing the same thing without jQuery, you can use .getElementsByClassname() or .querySelectorAll() if you don't care about supporting older browsers.
jQuery IS Javascript. You can mix and match them together. But you better know what you're doing.
In this case, you probably want to use .attr function to set value of attribute.
Use .attr() in jQuery, rather than mix the two here.
$('.nav_flag').attr('src', "images/flags/"+userCountryLower+".gif");
In many instances, it is fine to mix jQuery with plain JavaScript, but if you have already included the jQuery library, you might as well make use of it. Unless, that is, you have an operation which in jQuery would be more computationally expensive than the same operation in plain JavaScript.
You can do it with jQuery too:
$('.nav_flag').attr("src", "images/flags/"+userCountryLower+".gif");
keep in mind that jQuery is simply a library built upon javascript.
for any jQuery object, selecting its elements by subscription will return the corresponding dom element.
e.g.
$('#foo')[0] // is equivalent to document.getElementById('foo');
You need to add an index to the jQuery object to get the native Javascript object. Change:
$('.nav_flag').src = "images/flags/"+userCountryLower+".gif";
To:
$('.nav_flag')[0].src = "images/flags/"+userCountryLower+".gif";
To get elements by class name in Javascript you can use:
document.getElementsByClassName( 'nav_flag' )[0].src = "images/flags/"+userCountryLower+".gif";
To answer your question, you could use .toArray() to convert the jQuery object into an array of standard DOM elements. Then either get the first element or loop through the array to set all the elements with the class.
However, you could do this easier with pure jquery with attr or prop depending on the version:
$('.nav_flag').attr("src", "images/flags/"+userCountryLower+".gif");
Or use pure javascript:
if (navFlagElements = document.getElementsByClassName("nav_flag") && navFlagElements.length > 0) {
navFlagElements[0].src = "images/flags/"+userCountryLower+".gif"
}

Using $.data() in jQuery to store flag on element

I am authoring a simple jQuery plugin that turns an input tag into a time-formatted element (on blur it will change 245p into 2:45 pm).
Since I do not want to apply the time format events to the same element twice, I need a way to detect that the specific element in the list provided has not already had the format applied.
This is the relevant part of the code:
var methods = {
init : function(sel) {
var $this = $(sel);
return $this.each(function(){
var data = $(this).data('time_formatted');
if (data) {
return;
} else {
$(this).data('time_formatted', true);
I have heard that using $(sel).data() in a plugin is not a good idea; instead, use $.data(). I don't know why, that's just what I've heard; honestly, I don't know what the difference is.
So my question is, is this the way to accomplish checking if a specific element has had the time formatter applied to it in a plugin?
If you care to see the plugin in it's current development state, see http://jsfiddle.net/userdude/xhXCR/.
Thanks!
Jared
Where have you heard that using .data() is not good? jQuery's plugin autoring page says:
Often times in plugin development, you may need to maintain state or check if your plugin has already been initialized on a given element. Using jQuery's data method is a great way to keep track of variables on a per element basis. However, rather than keeping track of a bunch of separate data calls with different names, it's best to use a single object literal to house all of your variables, and access that object by a single data namespace.
So it should be perfectly fine.

pulling an array of objects

I currently have a validation script that has a selection of <input> elements stored in objects with properties such as "id", "type" "isRequired" and"isValid". I currently have this setup() function that does the following:
function setup(obj) {
obj.getElement().onkeyup = function() {validate(obj)}
}
In order to run this setup() function on all of my input objects I need to execute the following addEvents() function
function setEvents() {
setup(firstName)
setup(lastName)
setup(email)
setup(dateOfBirth)
}
I'm helping create a system that has multiple pages of nothing but forms so I'd prefer if I didn't have to type this for each object. Is there a way I can collect an array of all the objects that are based on a specific object template? This way I could loop through the array and apply a setup to each object in a single function. If not, are there alternatives?
(p.s. I've been asking so many object-oriented(oh, I crack myself up sometimes) questions lately because this is my first time messing with objects)
---Edit---
the object template I'm referring to looks something like this:
function input(id,isRequired,type) {
this.id = id
this.isRequired = isRequired
this.type = type
}
this is then followed by a
firstName = new input('firstName',true,'alpha')
As I said in my comment, you could add the element to an array when you create it:
var inputs = [];
var firstName = new input('firstName',true,'alpha');
inputs.push(firstName);
This is not ver convenient yet. But you could create another object which manages all this:
var InputManager = {
elements: [],
create: function(/* arguments here */) {
var n = new input(/* arguments here */);
this.elements.push(n);
return n;
},
setup: function() {
for(var i = this.elements.length; i--;) {
(function(obj) {
obj.getElement().onkeyup = function() {validate(obj)};
}(this.elements[i]));
}
}
};
with which you can do:
var firstName = InputManager.create('firstName',true,'alpha');
// etc.
InputManager.setup();
Something along these lines. I think this would be a quite object oriented way. If you have a collection of objects, you often have another object which handles the functions that should be performed on all those objects.
As with most javascript questions, the easiest way to do this is with a library such as jQuery. If you have a unique way to differentiate these objects with a css selector (e.g., they all have the class "validate" or they're the only input[type="text"] fields on the page or something), then you can do a simple selection like $('.validate') to get an array of all these objects. You can get this array using javascript of course but it's a tad more complicated. Once you have the array you can loop over the elements or you can do a simple bind like $('.validate').change(validate); which will call the validate() method whenever a dom element with the class 'validate' changes.
Edit: So obviously I don't know the entirety of what you're trying to accomplish, but if you're new to web programming, just note also that no matter what you're doing on the client side (ie in the browser), all validation should also be done on the server side. Javascript validation is generally used to just be user-friendly and not to actually validate your inputs, since I could easily just turn javascript off or redefine validate as function validate() {} and bypass javascript validation for whatever reason.
2nd Edit: So I'm not sure if this answer was 100% what you're looking for but it's good to know regardless.
Judging by your examples you are not using jQuery. And for that reason alone, I'm going to up vote you. On the same note, after you get really comfortable with JS and how you can do things, really consider using a framework or saving your scripts so you don't have to reinvent the wheel for each project.
You can actually use the DOM to your advantage!
All the forms in your page can be referenced with document.forms[index]. Alternatively you can also reference a named form with document.formName.
Look at this jsfiddle for an example using the latter.
UPDATE
Reading your update and the fact that you needed a way of creating the input objects and setup the validation. I updated my fiddle with a different approach.
Used the id to hold the validation info regarding the element then the addValidation function reverts the id to it's basic form so you can still use it normally throughout your application.
The only requirement is that you addValidation the first thing after page load. So the ID get revamped first.
The solution is also JS safe, meaning if the user doesn't have JS, apart from no validation, no other things will happen.
I think your problem is that the obj in the onkeyup scope is undefined.
function setup(obj) {
//obj is desired
obj.getElement().onkeyup = function() {validate(obj) //obj is undefined because onkeyup is the new scope of this function
}
instead you could do this:
function setup(obj) {
obj.getElement().onkeyup = function() {validate(this)
}

Categories

Resources