Replacing the source attribute of multiple JQuery selectors - javascript

I'm trying to get it when a button is clicked, all buttons are given the Off state, (src is btnCircuitxOff.gif) and the one selected is given the On state (src is btnCircuitxOn)
That is clicking one will deselect the others and select itself, this is only visual feedback for a physical device on the other end of an ajax query, otherwise I would use radio buttons themselves.
So far I have,
Html / css
<div id='controls'>
<input type="image" class = "Circuit _100" src="btnCircuit100Off.gif" onclick="selectCircuit('100');"/>
<input type="image" class = "Circuit _10K" src="btnCircuit10KOff.gif" onclick="selectCircuit('10K');"/>
<input type="image" class = "Circuit _100K" src="btnCircuit100KOff.gif" onclick="selectCircuit('100K');"/>
<input type="image" class = "Circuit _1M" src="btnCircuit1MOff.gif" onclick="selectCircuit('1M');"/>
<input type="image" class = "Circuit _10M" src="btnCircuit10MOff.gif" onclick="selectCircuit('10M');"/>
<input type="image" class = "reset" src="btnReset.gif" onclick="reset();"/>
</div>
Javascript
function selectCircuitButtons(s)
{
$(".Circuit").attr("src",$(".Circuit").attr("src").replace("On","Off"));
$("._"+s).attr("src",$("._"+s).attr("src").replace("Off","On"));
}
Which almost seems to work, except that as soon as I click something, every image gets replaced with btnCircuit100Off instead of their individual btnCircuitxOff images.
I'm almost sure I almost have a solution, but how can I store each selector to use when editing the src element?
I've looked at .each and $(this) but I'm new to JQuery and am having troubles formulating a solution.
Also suggestions for a good title are welcome.

You need to read the current value of the attribute for each element, rather than always reading a single value.
To help you with that, jQuery allows you to pass a callback:
$(".Circuit").attr("src",
function(elem, oldSrc) { return oldSrc.replace("On","Off"); }
);

You can use $.each to iterate through each matching item
function selectCircuitButtons(s) {
$(".Circuit, ._"+s).each(function(index,item){
$(item).attr("src",$(item).attr("src").replace("On","Off"));
});
}

You need to iterate through circuite using $.each
You have to toggle each image name along element has class or not:
function selectCircuitButtons(s) {
$(".Circuit").each(function() {
var hasS = $(this).hasClass("_"+ s);
if(hasS) {
$(this).attr("src", $(this).attr("src").replace("Off","On"));
} else {
$(this).attr("src", $(this).attr("src").replace("On","Off"));
}
});
}
EDIT simpler (with #SLaks technique):
function selectCircuitButtons(s) {
$(".Circuit").attr("src", function(elem, oldSrc) {
return $(elem).hasClass("_"+ s) ?
oldSrc.replace("Off","On") : oldSrc.replace("On","Off");
});
}

Related

How to run the same function (but class changes) on multiple IDs jQuery

I have the following jQuery code:
jQuery("#box1").focusin(function() {
jQuery(".grid_location1").show();
}).focusout(function () {
jQuery(".grid_location1").hide();
});
jQuery("#box2").focusin(function() {
jQuery(".grid_location2").show();
}).focusout(function () {
jQuery(".grid_location2").hide();
});
HTML
<input type="text" name="homepage_grid_box_1[box1]" class="box" id="box1">
<div class="grid_location grid_location1"> </div>
This repeats for every ID I have on the page i.e there is 15. I feel this cannot be the correct way to go about this and instead there has got to be a more efficient method. I wasn't sure if a loop with a counter would work and had a go but it wasn't working.
Any ideas?
You should better abandon the use of incremental id values like "box1", "box2", ...
Instead use a class "box" and assign that to those 15 box1, box2, ... box15.
For the same reason, incremental classes like "grid_location1", "grid_location2" are to be avoided. Just call them "grid_location". The context of where they are used, should be enough to isolate those that relate to a certain box element.
Either the box element contains the corresponding "grid_location" element(s), or you should create a container element (like a span) with a particular class ("container") that contains both one "box" element and the corresponding "grid_location" element(s).
Now that you added the HTML to your question, it is clear that those elements do not have a common parent, but are siblings. You can make it work with .next() as follows:
jQuery(".box").focusin(function() {
jQuery($(this).next()).show();
}).focusout(function () {
jQuery($(this).next()).hide();
});
A more reliable approach is to add container elements (with class "container"), like this:
<span class="container">
<input type="text" name="homepage_grid_box_1[box1]" class="box">
<div class="grid_location"> </div>
</span>
And then do:
jQuery(".box").focusin(function() {
jQuery(".grid_location", $(this).closest(".container")).show();
}).focusout(function () {
jQuery(".grid_location", $(this).closest(".container")).hide();
});
you can use with comma seperated id's
jQuery("#box1, #box2, #box3").focusin(function() {
jQuery(".grid_location1").show();
}).focusout(function () {
jQuery(".grid_location1").hide();
});

Get multiple attributes with .attr() to get both "id" and ":checked" from element using "this" | jQuery

my question is very simple and doesn't seem to be around as often as setting or applying value in multiple cases.
Using $(this) how can I achieve to get multiple attributes from a single element using as the title informs simply .attr().
$(this).attr('id', "checked") // Pseudo code
For the use to be stored in an array or variable for example. Thank you.
The syntax you used will set the value to the attribute. Hence, you can use
something like ['id', 'checked'].map(a => $el.attr(a)) as mentioned by lxe in the comment or you can create a jQuery wrapper attrs as below.
To get the value of checked property, you can use prop as below instead of attr.
Working snippet:
$(document).ready(function() {
$.fn.attrs = function() {
return Object.keys(arguments).map(k => $(this).prop(arguments[k]));
};
$('input[type="checkbox"]').click(function() {
globalCallback($(this).attrs('id', 'checked'));
});
});
function globalCallback(attrs) {
console.log(attrs);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Click the checkbox and see the console:
<br/>
<input type="checkbox" id="checkbox1" /> Checkbox 1
<input type="checkbox" id="checkbox2" /> Checkbox 2
<input type="checkbox" id="checkbox3" /> Checkbox 3
You can't do this, according to jQuery documentation:
Get the value of an attribute for the first element in the set of matched elements.
Moreover your $(this).attr('id', "checked") code will set to the id attribute the checked value, since attr can be used to set values with exactly such syntax.
However you can create a helper methods like the one mentioned by lxe
You can get the attributes using Array#reduce on the Element.attributes to create an object of attributes:
// get all elements attributes, and convert them to array
var attributes = [].slice.call($('#v-box').get(0).attributes, 0);
// reduce the array to key value pairs
var object = attributes.reduce(function(r, attr) {
r[attr.name] = attr.value;
return r;
}, {});
console.log(object);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="v-box" type="checkbox" checked="checked">
You can easily extend the jQuery function to accommodate what your looking for.
If you aren't interested in extending you could create a new function/ plugin as well
Here's an example:
(function($)
{
var oldAttr = $.fn.attr;
$.fn.attr = function() {
var args= arguments[0];
if(Object.prototype.toString.call(args)=="[object Array]") {
return [args.map((e=> oldAttr.apply(this, [e])))];
//if you want to get a string you could just try `return args.map((e=> oldAttr.apply(this, [e])))`
}
return oldAttr.apply(this, arguments);
};
})(jQuery);
Demo: https://jsfiddle.net/eztukwj9/

angularjs: Change checkbox to image on selection

I want to implement a functionality in which, whenever a user checks a checkbox, it will get replace with a check image. For example:
So if I select first option it should get replace with a check image.
I am able to replace the checkbox with image, but this new element looses the ng-click event.
Below is the code:
currentController.changeChoice = function ($event, value) {
if ($event.target.checked) {
currentController.selectedOptions.push(value);
$($event.target).replaceWith('<div ng-click="stock.changeChoice($event,option);"><img src="../images/check.png" alt="remove" ng-checked="stock.selectedOptions.indexOf(option) > -1" /> </div>');
}
else {
var index = currentController.selectedOptions.indexOf(value)
currentController.selectedOptions.splice(index, 1);
}
};
below is the html generated for the new element (image)
<div ng-click="stock.changeChoice($event,option);"><img src="../images/check.png" alt="remove" ng-checked="stock.selectedOptions.indexOf(option) > -1"></div>
If angular way you have to use ng-show(or ng-if) for hide or show image and checkbox depends of the state. They both have to use same on-click callback. Here is the basic idea on pseudocode
<input ng-show="!is_checked" ng-click="callback()" ... />
<img ng-show="is_checked" ng-click="callback()" ... />

How can I create a css glow effect with javascript?

What I'm going after is a code that will gather all my text input fields and detect whether or not they have any input. If so I'd like for there to be a glow effect added, if they're left empty or they delete the data and leave it empty I'd like for the glow effect to turn off.
So far from everything I've found this is what I came up with so far, it doesn't work of course, but it's the best I could try to rationalize.
function glow(){
var text = document.getElementsByClassName('tex_inp01 tex_inp02');
if (text.value ==null){
text.style.boxShadow="#8fd7d2 0px 0px 22px";
}
else
remove.style.boxShadow;
}/**function**/
I used the .getElementsByClassName because the getElementsById didn't support multiple IDs as it seems, but if there's another more efficient way of gathering them all please share.
Simple solution can be adding class having glow with javascript:
var text = document.getElementsByClassName('tex_inp01 tex_inp02');
text[0].className = text[0].className + " glow";
DEMO
Note: If you want to add glow class to each input then you have to iterate through loop and add class to each element. Because text is
HTMLCollection of elements.
You need to get the value of each element, not of the HTMLCollection returned by document.getElementsByClassName; Array.prototype.forEach can help with this. Then, a value can’t be null, but empty.
Edit: Wait a minute… you want the glow effect if the element has an input, right? Then your if-else statement is the wrong way around.
This is the correct function:
function glow() {
"use strict";
Array.prototype.slice.call(document.getElementsByClassName("tex_inp01 tex_inp02")).forEach(function(a) {
if (a.value !== "") {
a.style.boxShadow = "0px 0px 22px #8fd7d2";
}
else {
a.style.boxShadow = "";
}
});
}
You have a couple of mistakes in your existing code (as presented in the question): (1) text.value ==null - do not check against null, because an inputs value will never be a null. Check its length. (2) remove.style.boxShadow; - I think that was a typo. It should have been text.style.boxShadow = 'none'.
..to be a glow effect added, if they're left empty or they delete the
data and leave it empty I'd like for the glow effect to turn off..
You can check if the input has been left empty by simply checking the length of the value. However, to check if the input has been entered and then deleted you will have to keep a flag to keep track of that. You can do that by hooking up the change event on inputs and then setting a flag via data attribute. Later when you are checking each input for applying a style, along with the length also check this attribute to see if the input was edited out.
Here is a simple example putting together all of the above (explanation in code comments):
var inputs = document.getElementsByClassName("a b"), // returns a collection of nodelist
button = document.getElementById("btn"); // just for the demo
button.addEventListener("click", checkInputs); // handle click event on button
[].forEach.call(inputs, function(elem) { // iterate over all selected inputs
elem.addEventListener("change", function() { // handle change event
this.setAttribute("data-dirty", true); // set a data attribute to track..
}); // .. a flag when it is changed
});
function checkInputs() {
[].forEach.call(inputs, function(elem) { // iterate over selected inputs
var isDirty = elem.getAttribute("data-dirty"); // check the dirty flag we set
if ((elem.value.length > 0) || (isDirty)) { // if empty or changed
elem.style.boxShadow = "none"; // reset the style
} else {
elem.style.boxShadow = "#f00 0px 0px 5px"; // else apply shadow
}
});
}
<input class="a b" /><br /><br /><input class="a b" /><br /><br />
<input class="a b" /><br /><br /><input class="a b" /><br /><br />
<button id="btn">Check</button>
If you wanted to validate the inputs while the user is typing, you can use keyboard events to check the value of the input(s):
document.querySelector('input[type="text"]').addEventListener('keyup',
function(event){
var element = event.target;
if (element.value.trim() === '') {
element.classList.add('empty');
} else {
element.classList.remove('empty');
}
});
See fiddle for example: http://jsfiddle.net/LrpddL0q/.
Otherwise this could be implemented the same way without the addEventListener to perform as a one-off function.
Jquery can help you as the following
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script>
$(document).ready(function () {
$(".MyInput").bind('keypress', function () {
$('.MyInput').css("boxShadow", "#8fd7d2 0px 0px 22px");
});
$(".MyInput").bind('keydown', function () {
if ($(".MyInput").val() == "") {
$('.MyInput').css("boxShadow", "none");
}
});
});
</script>
HTML:
<input type="text" value="" class="MyInput" />
this code working only online If you need to download Jquery library visit this
https://jquery.com/download/

How to dodge a DRY issue when calling a function with a constant?

I am still new to Javascript. I need to attach a function to handle events on some of my HTML elements.
I am doing the following:
$('#iinp0').keyup(function(){keyReleased('iinp0');});
$('#iinp1').keyup(function(){keyReleased('iinp1');});
$('#iinp2').keyup(function(){keyReleased('iinp2');});
$('#iinp3').keyup(function(){keyReleased('iinp3');});
$('#iinp4').keyup(function(){keyReleased('iinp4');});
$('#iinp5').keyup(function(){keyReleased('iinp5');});
$('#iinp6').keyup(function(){keyReleased('iinp6');});
$('#iinp7').keyup(function(){keyReleased('iinp7');});
I was hoping I could apply the Don't Repeat Yourself (DRY) principle with the following:
for (i=0;i<=7;i++) {
var tmp = 'iinp' + i;
$('#'+tmp).keyup(function(){keyReleased(tmp);});
}
but keyReleased() is not called with the proper values.
Is there a solution to this issue? I mean is there a simple way to attach my functions having a constant parameter?
Why not simply this:
$('#iinp0, #iinp1, #iinp2, #iinp3, #iinp4, #iinp5, #iinp6, #iinp7').keyup(function()
{
keyReleased(this.id);
});
You could even replace that long selector with an attribute selector:
$('[id^=iinp]').keyup(function()
{
keyReleased(this.id);
});
which will select any element who's id starts with iinp.
Note: This selector is a tad slower than the pure ID selectors - but is much easier to read and maintain (if you could qualify it with a tag selector, it'll be a bit faster).
In your case this would be the best:
$('[id^="iinp"]').keyup(function()
{
keyReleased(this.id);
});
But you may like to hear the reason it doesn't work: it's because JavaScript binds the tmp var to the bigger scope.
The following code works because we are explicitly binding the current value of tmp to the new function being created:
for (i=0;i<=7;i++) {
var tmp = 'iinp' + i;
$("#"+tmp).keyup((function(xtmp){ return function(){keyReleased(xtmp);} })(tmp));
}
Don't use numbered ids.
Instead use a class.
$('.iinp').keyup(function() {
var index = $(this).index('.iinp');
keyReleased('iinp', index);
});
HTML
<input class="input" id="iinp0" />
<input class="input" id="iinp1" />
<input class="input" id="iinp2" />
JS
$(function(){
$('.input').keyup(function() {
keyReleased(this.id.replace('iinp', ''));
});
function keyReleased(key) {
console.log(key)
}
})
Assuming each one of your inputs have the same class, or are the same element type (like input), you can assign them all to the same function using a selector and the on() function, and pass the id of the element to the keyReleased() function:
Example HTML:
<div id="formData">
<input type="text" id="iinp0" \>
<input type="text" id="iinp1" \>
</div>
jQuery JavaScript:
$("#formData").on("keyup", "input", function() {
keyReleased($(this).attr('id'));
});
http://jsfiddle.net/4SKgU/
The rest of these answers will do what you want, but personally I'd go a step further to reduce the amount of anonymous functions being made (although, some approaches will not do that):
Use classes for your input
<input class="keyup" id="iinp01" />
Bind using class and non-anonymous event handler
(function ($) { // closure
$(function () { // on document ready
$("input.keyup").keyup(keyReleased);
});
function keyReleased(e) {
var id = this.id,
$input = $(this);
// Do whatever you want
}
})(jQuery);
Hopefully that will help. If you aren't familiar with closures, learn about them!
If possible, I'd also provide a parent element for context:
<div id="keyup-container"><!-- inputs here --></div>
$("#keyup-container input.keyup")
It will be more efficient (if you are worried about that).

Categories