Binding multiple events to elements stored in variable - javascript

I know that puting reference of HTML element into the variable is a good practice if I need to reference to this element many times. But I run into the problem with this while making my project. How can I bind multiple and the same events to the elements which are stored into the variable?
For now I deal with it this way:
var producerEl = $("#js-producer");
var brandEl = $("#js-brand");
var seriesEl = $("#js-series");
bind(seriesEl);
bind(brandEl);
bind(seriesEl);
function bind($el) {
$el.on("keypress", function () {
// some code..
});
}
I need something like $(producerEl, brandEl, seriesEl).on...

var producerEl = $("#js-producer");
var brandEl = $("#js-brand");
var seriesEl = $("#js-series");
producerEl.add(brandEl).add(seriesEl).on("click", function () {
alert('hello');
});

If you are trying to keep your code readable, might I suggest this approach?
$("#js-producer, #js-brand, #js-series").on('keypress', function () { });

Hmm. If you're using these selectors only one, don't care about "I know it is good to". The best solution is the one provided by David Smith.
Anyway, jQuery is using the sizzle selector engine, who has it's own cache. You can ask for
$("#js-producer, #js-brand, #js-series")
the result would be cached and reused.

Related

How to make variable accessible within jQuery .each() function?

This is and example of a frequent dilemma: how to make markup accessible inide this .each()?
I'm more interested in learning how to access outer variables from within a closure than I am in this specific issue. I could fix this problem by assigning markup from inside the each function, but I'd rather learn a more elegant way to handle this kind of problem.
// hide form & display markup
function assessmentResults(){
// get assessment responses
var markup = parseForm();
// show assessment results to user
$('#cps-assess-form fieldset').each( function() {
var q = $(this).find('.fieldset-wrapper');
var i = 0;
// hide form questions
q.slideUp();
// insert markup
$('<div>'+markup[i]+'</div>').insertAfter(q);
i++;
});
}
Read the docs, it already has an index!
.each( function(index, Element) )
No need for i
$('#cps-assess-form fieldset').each( function(index) {
var q = $(this).find('.fieldset-wrapper').slideUp();
$('<div/>').html(markup[index]).insertAfter(q);
});
The reason why yours is failing is the i is inside of the function so it is reset every iteration. You would need to move it outside of the function for it to work.

Using javascript:function syntax versus jQuery selector to make Ajax calls

I do front-end dev only like 10% of the time and am curious which is the better way to handle making ajax calls. These calls are just posting data to a web app that specifies an action name and an id.
<a href='javascript:addToList({'action':'set-default-time-zone','id':23})'>set default timezone</a>
<div class='add-to-list action-set-default-time-zone id-23'>set default timezone</div>
I have used both over the years but am not sure which one is preferred. It seems like they get to the same point in the end. Would you consider these to be the two best alternatives and is one better than the other?
I've implemented the div method as follows:
$(document).ready(function(){
$('.add-to-list').click(function(){
var id=getId($(this).attr("class"));
var action=getAction($(this).attr("class"));
$.post('/api/' + action,function(data){
...
},'json')
});
});
function getAction(str){
var parts=str.split(' ');
var phrase='action-';
for(i=0; i<parts.length; i++){
var val=parts[i].match(phrase);
if(val!=null){
var action=parts[i].split('action-');
return action[1];
}
}
}
function getId(piece){
var parts=piece.split('id-');
var frag_id=parts[parts.length-1];
var part_id=frag_id.split('-');
var id=part_id[part_id.length-1];
return id;
}
The link method would seem straightforward.
thx
Well the second approach is what you would call Unobtrusive JavaScript. It is believed to be a more robust approach (I'll avoid the term better here.)
However, your implementation is a bit over-complicated. It could be tuned down to:
HTML:
<div class="add-to-list" data-action="set-default-time-zone" data-id="23">
set default timezone
</div>
JavaScript:
$(document).ready(function () {
$('.add-to-list').click(function () {
var id = $(this).attr("data-id");
var action = $(this).attr("data-action");
$.post('/api/' + action, function(data) {
// ...
}, 'json')
});
});
The HTML5 specification allows for attributes starting with data- to be carrying user-defined data. And it's also backward compatible (will work with older browsers.)
Method 1:
<a href='javascript:addToList({'action':'set-default-time-zone','id':23})'>set default timezone</a>
Method 2:
<div class='add-to-list action-set-default-time-zone id-23'>set default timezone</div>
Method 2 is preferred because you would be practicing unobtrusive style of coding with a much clearer separation of your markup and your scripting code. It is alot easier to read and debug, and there for more maintainable. Also, i would propose instead of using CSS classes to pass data, to use the jQuery.data() method to store data on elements.

A function and a form of encapsulation?

I'm sorry if this question has been asked before, but I'm not even sure what search terms to use to find the answer and when I try to search I never get anything specific to this question.
I'm using Javascript and I am wondering if it is possible to do something like this:
find(x); // find a document (for example)
find.inFolder(y); // find a folder's documents (for example)
In other words, can I have a function that can also be used as an object/class? I know I could run find() once and return a hash so that find.inFolder() would work, but I'm hoping there's a way where I could continue to call find().
Can it be done with prototype? (my "prototype" knowledge is very limited)
function find() {}
find.prototype.inFolder = function() {}
Can it be done inside a hash? [I know this code doesn't work]
var find = {
() : function() {},
inFolder : function() {}
}
To push it even further, is there a way to have the results of .inFolder() be sent to the find() function this way:
find().inFolder();
I know you might say that I don't understand the concept of javascript, and you'd be mostly correct, but I've seen people do some pretty amazing stuff with JS so I thought I'd ask the pros out there.
Thanks in advance for any help.
What you're describing is a Fluent interface (if you want something to search for). You could accomplish something like what you're trying to achieve like this:
var find = function() {
this.inFolder = function() {
return this; // Although to stop chaining, you could return nothing here.
};
return this;
};
find().inFolder(); // .inFolder().inFolder()...
This is a great pattern, especially when leveraged in projects like jQuery:
$("#element").find(".child_element").first();
Each call returns a jQuery object with .find(), .first() and many other functions, which lets you write intuitive and fluid code.
I kind of liked your find().inFolder() example, so here's an expanded version:
var find = function(file) {
this.folders = {
"Documents": ["Foo.txt", "Bar.txt"],
"Downloads": ["File.exe"],
"Misc": ["Picture.jpg"]
};
this.file = file;
this.inFolder = function(folder) {
var files = this.folders[folder];
return files.indexOf(this.file) >= 0;
};
return this;
};
alert(find("Foo.txt").inFolder("Documents")); // True
alert(find("File.exe").inFolder("Downloads")); // True
alert(find("Picture.jpg").inFolder("Downloads")); // False
http://jsfiddle.net/andrewwhitaker/TCdTd/
You can assign, a function to a member of another function:
find = function(x) { .... }
find.inFolder = function(y) { ... }
jsFiddle.
I'm not sure I understand the question however.

JS syntax to bind 2 objects to the same function calls

*update: sorry for the vagueness. I have updated the question
I am using the pusher library, where i create channels and bind it to a function (http://pusherapp.com/docs/quickstart)
var myChannel = pusher.subscribe('MY_CHANNEL');
myChannel.bind('thing-create', function(thing) {
//executes
});
In this case, i have 2 objects that subscribe to different channels, but execute the same set of function.
var myChannel = pusher.subscribe('MY_CHANNEL');
var myChannel2 = pusher.subscribe('MY_CHANNEL2');
//wondering if there is syntax for something like this
(myChannel+myChannel2).bind('thing-create', function(thing) {
//executes
});
I can certainly just repeat it, but I know you can do it in jQuery, so i wonder if there is a way to do this for js objects. Maybe jQuery just iterates the the elements
//in jquery, you would do this
$(".xxx",".xxx").bind(...)
var f = function() {...};
a1.bind("xx", f);
a2.bind("xx", f);

javascript jquery: Overwriting variables - how? better performance?

Hey guys,
i'm not much of a hardcore coder and so I don't get this basics here.
Imagine I have multiple 's on my page (that contain Youtube Videos via swfobject).
All those object's have a unique ID like ytplayer_12, ytplayer_2, ytplayer_56, etc.
I need to run through all of this ytplayer_'s with jquery and add an EventListener to them.
It works just fine! I just wonder if I'm declaring the variables ($ytid, ytid) in the right place - outside of the onYouTubePlayerReady() function? Or should I declare the vars inside of the function? Or even inside of the each-loop?
var $ytid = '',
ytid = '';
function onYouTubePlayerReady() {
$('object[id^="ytplayer_"]').each(function() {
$ytid = $(this).attr('id');
ytid = document.getElementById($ytid);
ytid.addEventListener("onStateChange", "foo");
});
};
I'm just curious what is better in this case and if I'm doing that correct right now?
Thank you for your info and help?
Declaring variables at global scope is bad idea. Move them into function scope.
function onYouTubePlayerReady() {
var $ytid = '', ytid = '';
$('object[id^="ytplayer_"]').each(function() {
$ytid = $(this).attr('id');
ytid = document.getElementById($ytid);
ytid.addEventListener("onStateChange", "foo");
});
};
And you can get rid of them:
function onYouTubePlayerReady() {
$('object[id^="ytplayer_"]').each(function() {
this.addEventListener("onStateChange", "foo");
});
};
Since the variables' values are unique to each iteration, you definitely need to define them inside the loop. Although you can make life a little easier for yourself and leave out the document.getElementById() call, since this is already pointing to the object you're looking for:
var ytid = this;
var $ytid = $(this).attr('id'); // only if you need the id for something other than instantiating the ytid variable
I used var as per gor's suggestion not to make the variables global

Categories