I have several fish images, within links, which are listed like so...
<img src="img/fish1.png" id="fish1"/>
<img src="img/fish2.png" id="fish2"/>
I want to take id 'fish1', 'fish2', ect. (based on which is clicked), and use a variable to replace some text.
The name of the variables are...
var fish1Hunger
var fish2Hunger
And the function I want to call with a variable is...
$(function() {
$('a.trigger').click(function() {
$('#popUp h3').html(REPLACE WITH VARIABLE ASSOCIATED WITH THE FISH);
});
});
How can I call the variable associated with the IMG id?
window[e.srcElement.id+"Hunger"];
Put that inside your click event with e being the event (function (e){...) and it should access the variable as long as it is in the global scope.
jsBin demo
var fish1Hunger = "Fish 1 is hunger!! Feed him!"
var fish2Hunger = "Fish 2 is hunger!! Feed him!"
$('a.trigger').click(function (e) {
e.preventDefault();
var ImLookingFor = $(this).find('img').attr('id')+'Hunger';
$('#popUp h3').html(eval(ImLookingFor));
});
Related
This question already has answers here:
Get global variable dynamically by name string in JavaScript
(6 answers)
Closed 5 years ago.
HTML:
<button id="s01" onclick="getMusic(this.id)"></button>
<button id="s02" onclick="getMusic(this.id)"></button>
JAVASCRIPT:
var s01 = ["file", "song"];
var s02 = ["file", "song"];
function getMusic(e){
alert()
}
Alright so I have this code above (This is a simplified version). This function will set e in getMusic(e) to either s01 or s02. I need to be able to call the variable that corresponds to that name (within the alert()) but I'm not even sure where to start. Any help is appreciated, thanks!
P.S. any chance I can remove the onclick="" from the HTML file and replace it with an addEventListener in the js file and still achieve the same effect? I don't like mixing my scripts like that.
If you use an object to hold your data, it's a lot easier
var data = {
s01 : ["file", "song"],
s02 : ["file", "song"]
};
function getMusic(e){
console.log( data[e] );
}
If you use addEventListener you can remove the inline javascript as well
var data = {
s01 : ["file1", "song"],
s02 :["file2", "song"]
}
document.querySelectorAll('.btn').forEach(function(el) {
el.addEventListener('click', function() {
console.log( data[this.id] );
});
});
<button id="s01" class="btn">Test 1</button>
<button id="s02" class="btn">Test 1</button>
First off, to answer your second question, yes, you can register the event listener in your JS:
document.querySelectorAll("input[type=button]").forEach(function(el){
el.addEventListener("click", getMusic)
})
Once you have your event handler registered that way, you can get the id of the button by accessing e.target.id.
function getMusic(e){
alert(e.target.id) // will alert with button id
}
At this point, you have a string containing the id; now you need to be able to pull the values that correspond to the id. It makes the most sense to defined a JSON bag with hashes corresponding to id.
var data = {
s01: ["your", "data"],
s02: ["your", "other", "data"]
}
function getMusic(e){
myData = data[e.target.id]
alert(myData)
}
In JavaScript, the window object exists, which contains all global variables.
Simply use window[e] to get your array's value:
var s01 = ["file", "song"];
var s02 = ["file", "song"];
function getMusic(e){
alert(window[e])
}
<button id="s01" onclick="getMusic(this.id)"></button>
<button id="s02" onclick="getMusic(this.id)"></button>
var = cooldynamicelement
How could I store the inner html I grab with jQuery from my div ie. <div class="username"> </div> to store as an accessible variable in jQuery eg. cooldynamicelement so I can grab and use at different areas of my site by just calling ie. $cooldynamicelement and updates with the dynamic .username element value.
1. Store HTML into localStorage
var dynamicElementHTML = localstorage.dynamicElementHTML || $(".username").html() || "";
localstorage["dynamicElementHTML"] = dynamicElementHTML;
To make it available to other pages a way would be to use the power of localstorage
https://developer.mozilla.org/en/docs/Web/API/Window/localStorage
If you're actually interested in the whole element (not only it's inner HTML) than instead of .html() use .prop("outerHTML")
2. Binding using jQuery (essential idea)
If you only want a way to reflect some variable HTML as actual html and make it alive you could do like:
var $myElement = $("<div />", {
class : "userData",
append : $someDynamicElements,
appendTo : $someParentElement,
on : {
contentUpdate : function() {
$(this).html( $someDynamicElements );
}
}
});
than whenever your $someDynamicElements changes you can trigger a contentUpdate
$myElement.trigger("contentUpdate")
3. Binding using jQuery (concept)
Here's the same elements binding concept gone wild:
// Here we will store our elements
var EL = {};
// Create desired HTML elements like this:
var LIST = {
username: $("<b/>", {
html : "UNKNOWN",
click : function() {
alert( $(this).text() );
}
}),
email: $("<a/>", {
html : "test#test.test",
href : "mailto:"+ "test#test.test"
}),
// add more here, you got the idea.
// don't forget that you can assign any JS / jQuery propery to your element.
// You can go insane using .on() and later .trigger()
};
// Our small "program" that replaces data-bind elements
// with dynamic elements from our list
$("[data-bind]").replaceWith(function(i){
var bind = this.dataset.bind;
if(!LIST[bind]) return;
if(!EL.hasOwnProperty(bind)) EL[bind] = [];
var klon = LIST[bind].clone(true)[0];
EL[bind].push(klon);
return klon;
});
// That's it. Now goes your code ///////////////
$(EL.username).css({color:"red"}); // just to test if it works :D
$("[data-target]").on("input", function(){
var target = this.dataset.target;
$(EL[target]).html( this.value );
});
// P.S: Even having thousands of elements inside EL
// say you have "EL.tableRows" you can do fabulously
// quick stuff like i.e: sorting, cause you iterate over a plain JS array.
// After the sorting of EL.tableRows is done and you need a jQuery
// representation simply use $(EL.tableRows).
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h2>Dynamic element Binding in jQuery</h2>
Enter some text and see the update trigger in different places<br>
<input data-target="username"><br>
Welcome <span data-bind="username"></span> !!<br>
You name is <span data-bind="username"></span> Click the red text!<br>
<span data-bind="email"></span>
Well if you want to have the jqueryObject in a variable, just do this:
$(function(){
window.$cooldynamicelement = $("div.username");
})
that way you're able to use $cooldynamicelement in a global context. If is that what you want. This way you're saving a reference to your .username element and thus every time you use it will be updated.
NOTE: If you decide to do this, be careful with polluting your global context.:
I know if I wanted to bind events to generated HTML, I'd need to use something like .on(), but I've only used it when binding events like .click().
I'm creating a web app that applys a list of colors. Colors are generated from a JSON file. Once fetched, I add it to the page, with certain information contained in attributes. I'd like to do something with the new generated HTML, which is list-elements. But what console.log() is showing me is there is nothing in the parent ul. Even though on the page I see the newly added content.
Here's the entire code based around it.
var setColors = function(){
getColors = function(){
$.getJSON('js/colors.json', function(colors) {
$.each(colors, function(i, colors) {
//console.log(colors);
$('<li>', {
text: colors['color'],
'name' : colors['color'],
'data-hex' : colors['hex'],
'data-var' : colors['var']
}).appendTo('#picker');
})
});
addColors();
}
addColors = function(){
var el = $('#picker').children;
$(el).each(function(){
console.log($(this));
});
}
return getColors();
}
$(function(){
setColors();
});
addColors() is where I'm having trouble with. The error says 'Uncaught TypeError: Cannot read property 'firstChild' of null. How can I work with the newly generated HTML?
You are missing parentheses on the children method:
var el = $('#picker').children();
Also, if you want the addColor method to be executed on the newly generated html, then you must add a call to it after the html is generated, from within the getJSON callback method.
addColors = function(){
var el = $('#picker').children;
$(el).each(function(){
console.log($(this));
});
}
A few issues:
missing end semi-color
missing parentheses on .children()
children() returns a jQuery object, no need for $(el)
Updated:
window.addColors = function(){
var $el = $('#picker').children();
$el.each(function(){
// do stuff here, but could attach each() to above, after children()
});
};
I'm working on a simple client side interface where I have a jQuery object that I want to access directly when clicking on a hyperlink. Simplified code:
<div class="controls">
<div class="score">
<a class="button" href="/add">Add points!</a>
</div>
</div>
$(".controls").myControls();
$.fn.myControls = function() {
return $.extend(this, $.myControls).initialize();
}
$.myControls = {
initialize: function() {
this.scoreElement = $("div.score", this);
this.linkElement = $("a", this.scoreElement);
this.scoreElement.score = 0;
var _this = this;
this.linkElement.click(function() {
_this.clickHandler(this);
});
},
clickHandler: function(element) {
var scoreElement = $(element).parent();
scoreElement.score = 1;
}
}
Explanation: .controls element has .score element which doubles as a container for score information (this.scoreElement.score). When I click on a link within the .score element, I find the parent element, which is the same element in the DOM as this.scoreElement and try to set its score property to 1. Obviously, this won't work, as the local scoreElement.score property in the clickHandler method is "undefined".
So here's my question: is there a simple way to access my this.scoreElement object directly through traversing the DOM with jQuery?
Surely I can check if this.scoreElement == $(element).parent() in some way and then access the right property in my this.scoreElement object, but direct access would be more elegant and robust. Is this possible? Am I going at it the wrong way? Thanks!
PS: Ignore the fact I use parent() to find the scoreElement, I only use it to illustrate my problem. Unless it is part of the problem, in that case don't ignore :)
While it's certainly possible to use your own 'control-object' to store the related data, I usually prefer to rely on jQuery doing it - with .data() method, like this:
$(this.scoreElement).data('score', 0); // in initialize()
$(this).parent().data('score', 1); // in clickHandler()
This approach allows me to scale more easily, as I never have to fear 'overlapping' issues, using a single 'control' object rather than object-for-element.
I would think that if you used jQuery's proxy function for your click handler, you then could just go this.scoreElement inside of clickHandler and you wouldn't even need to traverse the DOM. Like this:
$.myControls = {
initialize: function() {
this.scoreElement = $("div.score", this);
this.linkElement = $("a", this.scoreElement);
this.scoreElement.score = 0;
this.linkElement.click($.proxy(this.clickHandler, this));
},
clickHandler: function(event) {
var element = event.target;
this.scoreElement.score = 1;
}
}
After progressive simplification (and storing the score slightly differently) I get the code below, in which scoreElement is discovered once per .controls div, then held in a closure to make it available to its corresponding click handler. You could alternatively use .closest() - see commented out line.
$.fn.myControls = function() {
return this.each(function() {
var scoreElement = $("div.score", $(this));
scoreElement.data('score', 0);
$("a", scoreElement).on('click', function() {
scoreElement.data('score', 1);//get scoreElement from closure formed by the outer "each" function.
//$(this).closest(".score").data('score', 1);//alternative to the line above, not requiring closure.
});
});
};
Call as in the question with:
$(".controls").myControls();
This is so trivial and unidimensional it doesn't really warrant, in its own right, a jQuery plugin. Unless there was some compelling reason for a plugin (eg. reuse or the need for closely related methods), then I would phrase it as follows :
$(".controls").each(function() {
var scoreElement = $("div.score", $(this));
scoreElement.data('score', 0);
$("a", scoreElement).on('click', function() {
scoreElement.data('score', 1);//get scoreElement from closure formed by the outer "each" function.
//$(this).closest(".score").data('score', 1);//alternative to line above, not requiring closure.
});
});
That's the same code with the plugin wrapper removed and attached directly to the same base jQuery object.
And if you really wanted, you could write the whole thing in three lines as follows:
$(".controls").find("div.score").data('score', 0).find("a.button").on('click', function() {
$(this).closest(".score").data('score', 1);
});
I want to set timeouts dynamically in jQuery. The dynamically set timeout functions need to use $("this"), but I can't seem to get it working.
An exmple:
$("div").each(function(){
var content = $(this).attr('data-content')
setTimeout("$(this).html('"+content+"')",$(this).attr('data-delay'));
});
http://jsfiddle.net/qmhmQ/
What is the best way to do this?
$("div").each(function(){
var content = $(this).attr('data-content'),
$this = $(this); // here $this keeps the reference of $(this)
setTimeout(function() {
// within this funciton you can't get the $(this) because
// $(this) resides within in the scope of .each() function i.e $(this)
// is an asset of .each() not setTimeout()
// so to get $(this) here, we store it within a variable (here: $this)
// and then using it
$this.html(content);
}, $this.attr('data-delay'));
});
DEMO
Your code should look like this:
pass a function instead of a string.
Explanation:
When passing a string to setTimeout you get problems, because it runs in a different scope than you original one, and thus you get errors.
use the jQuery data()method
$("div").each(function(){
var content = $(this).attr('data-content'),
$el = $(this),
setContent = function(){
$el.html(content);
}
setTimeout(setContent,$el.data('delay'));
});
You can assign a function to a variable and pass that variable as parameter to setTimeout, this is the cleanest way.
Use closures (some tutorials).
Using strings with setTimeout is not a good idea. Also beware this, since it can change its context (ie. call-site) if used inside a closure.
If using data attributes you can use the jQuery data function.
$("div").each(function() {
var instance = $(this);
var content = instance.data('content');
var method = function() {
instance.html(content);
};
setTimeout(method, instance.data('delay'));
});
div {
border: 1px solid black;
margin: 5px;
height: 1.5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-content="fus" data-delay="1000"></div>
<div data-content="ro" data-delay="2000"></div>
<div data-content="dah" data-delay="5000"></div>
I am just expanding answer one above,
Use class or id to refer div in JavaScript. This will avoid further tag name conflicts in the page.
So your updated HTML is,
<div data-content="fus" data-delay="1000" class="dv"></div>
<div data-content="ro" data-delay="2000" class="dv"></div>
<div data-content="dah" data-delay="5000" class="dv"></div>
Now your updated JavaScript code is,
$(".dv").each(function(){
var content = $(this).attr('data-content'),
$this = $(this);
setTimeout(function() {
$this.html(content);
}, $this.attr('data-delay'));
});
Where main line is
$this = $(this);
Where we are assigning the current element to our variable used in the setTimeout function.
Please refer this link
Take $(this) out of settimeout and save that in local variable say 'self' just after $("div").each(function(){ this line
var self=$(this);
and use that self further.
The following seems like a good compromise of whitespace, readability and revealing intention.
$('div').each(function(){
var element = $(this)
var content = element.attr('data-content')
var delayms = element.attr('data-delay')
var action = function() { element.html(content) }
setTimeout(action, delayms)
})
SEE: http://jsfiddle.net/wilmoore/LSs6g/