I have a set of variables that I use to tell if an question in a survey has been answered, and they are initially set to false: q0=false; q1=false; qX=false;. Then in the body, I have several input type="radio"s with .change(function(){ counter_radio(q#,INPUT'S_ID); }); binded to each. This is the code for function counter_radio():
function counter_radio(q,id){
if (q===false) {
q=true;
count++;
$("#counter").css("width", count);
$("#percent").text(count + "%");
}
$("span#"+id).append(", "+q);
$("span#"+id).fadeIn();
}
I expect that the counter to only increment once (the first time a radio from a set is selected). However, the counter is incrementing every time the input type=radio changes. My problem is that, q returns true, but q# remains false. In php, I would make q a reference to q# so when q is set to true, q# is also set to true. Is there such a construct in javascript?
You could change your bound function to:
.change(function(){ q# = counter_radio(q#,INPUT'S_ID); });
and add a return q; to the end of your counter_radio function.
As others have said, simple variables like booleans are passed by value, not by reference in Javascript so there is no way to change that.
If you have multiple variables like this:
var q0=false, q1=false, qX=false;
then, it might be easier to put them in an array:
var qArray = [false, false, false];
Then, because arrays and objects are passed in a way that you can modify the original, you can pass the array and an index to your function like this and you are then able to modify the original data from your function:
function counter_radio(q, index, id){
if (q[index] === false) {
q[index] = true;
count++;
$("#counter").css("width", count);
$("#percent").text(count + "%");
}
$("span#"+id).append(", " + q[index]);
$("span#"+id).fadeIn();
}
counter_radio(qArray, 2, id);
There's no native syntax for that, but you can e.g. use objects for that:
function counter_radio(q_,id){
if (q_.ref===false) {
q_.ref=true;
count++;
$("#counter").css("width", count);
$("#percent").text(count + "%");
}
$("span#"+id).append(", "+q);
$("span#"+id).fadeIn();
}
I would collect the values when the user submits the form:
jQuery('radio[name=...]:checked').val()
If you want to warn the user that not all questions have been answered, use the jQuery validation plugin.
Related
I've seen lots of questions about passing objects by reference in Javascript, but not the object and properties by reference. Is it possible?
Right now I only found a way to do it by going through some type of logic like this, which is terribly inconvenient:
let multipliers = {
none:1,
sin:2,
cos:3,
tan:4,
atan:5,
}
incMultiplier(shapesMovements[index], "rotation", "x", "sin")
function incMultiplier(shapeMovement, kind, dimension, multiplier){
var numOfKeys = Object.keys(multipliers).length;
if(kind === "rotation"){
if(dimension === "x"){
if(multiplier === "sin"){
if(shapeMovement.rotation.x.multiplier !== numOfKeys){
shapeMovement.rotation.x.multiplier += 1
}else{
shapeMovement.rotation.x.multiplier = 1
}
}
}
}
}
I'd just like to increase the property value by one with whatever object and property I've thrown into that function.
I've seen another post where you can pass parameters, but this looks to assemble a new object, and is not by reference. I need to actually edit the values on the object's properties.
Originally, this is what I was trying, and it did not seem to alter the object on a global level. Only locally to the function:
incMultiplier(shapesMovements[index].rotation.x.multiplier)
function incMultiplier(multiplier){
var numOfKeys = Object.keys(multipliers).length;
if(multiplier !== numOfKeys){
multiplier = multiplier + 1
}else{
multiplier = 1
}
// always results in the same number.
// Does not keep increasing every time the function is called.
console.log(multiplier);
}
Originally, this is what I was trying
You're not passing an object with its properties there. You're passing the value of a single property, and assignments to multiplier do indeed just overwrite the local variable in the function. You need to pass an object and explicitly assign to its property:
function incMultiplier(valueObj) {
var numOfKeys = Object.keys(multipliers).length;
if (valueObj.multiplier !== numOfKeys) {
valueObj.multiplier++;
} else {
valueObj.multiplier = 1
}
}
incMultiplier(shapesMovements[index].rotation.x)
incMultiplier(shapesMovements[index].position.x)
incMultiplier(shapesMovements[index].rotation.y)
incMultiplier(shapesMovements[index].rotation.z)
It's not necessary to pass the whole shapesMovements objects and everything nested within them, passing a single mutable object is enough.
I am programming in Polymer 1.0 and am trying to create an IF function to change the value of a property. My function is the following:
_searchButton: function(selectednamedropdown, selectedtypedropdown){
if (selectednamedropdown=="no_name_selected" && selectedtypedropdown=="no_type_selected"){
this.searchUsagesBtn = true
} else{
this.searchUsagesBtn = false
}
}
In my mind when selectednamedropdown is equal to "no_name_selected" and selectedtypedropdown is equal to "no_type_selected" the function should set searchUsagesBtn to true and when they are not these values, false.
However, the function does not ever seem to be returning true even when these conditions are met. Any ideas why this might be? Thanks for all help
When I run your function like this:
let searchUsagesBtn;
function search(selectednamedropdown, selectedtypedropdown) {
if (
selectednamedropdown === "no_name_selected" &&
selectedtypedropdown === "no_type_selected"
) {
searchUsagesBtn = true;
} else {
searchUsagesBtn = false;
}
}
search("no_name_selected", "no_type_selected");
console.log("button: ", searchUsagesBtn);
I get button: true in console log. So maybe your inputs in this function are not a strings.
The issue was around how JavaScript treats properties within functions. The function was storing the new value and old value of the first property and not any values of the second property. The solution involved making 2 functions to test the strings in each property. Thanks for all assistance
I have an array that contains dates. and for some reason I can't get it to show on my screen I've been debugging for a few days now and I've tracked it down to a single line, but the line has worked before and I can't figure out what the issue might be.
The array looks like this:
var selectItems =
[ "05-26-2017", "06-02-2017", "06-09-2017",
"06-16-2017", "06-23-2017", "06-30-2017", "07-07-2017", "07-14-2017",
"07-21-2017", "07-28-2017"...];
It's passed as an argument from another function, but that's how it's showing in console.log().
I might be going about this the wrong way, maybe even a lot further around then I need to but this is what I've come up with:
1. function setTHead(selectItems) {
2 var formatString;
3. for (var x = 0; x < 12; x++) {
4. formatString = selectItems[x].replace(/[^0-9/-]/g, "").toString();
5. console.log(selectItems);
6. $('#datTab').append("<div id='col" + x + "' class='column'>'" + formatString + "'</div>");
7. }
8. }
the array up top is what's showing from the console.log 5 lines down.
the sixth line is what is seeming to give me issues. Nothing is put on the page at all.
I'm getting a console error saying:
jQuery.Deferred exception: selectItems is undefined setTHead#http://localhost/mySite/script.js:136:9
startUp2#http://localhost/mySite/script.js:146:5
#http://localhost/mySite/table.php:19:9
mightThrow#http://localhost/mySite/lib/jquery.js:3586:52
resolve/</process<#http://localhost/mySite/lib/jquery.js:3654:49
setTimeout handler*resolve/<#http://localhost/mySite/lib/jquery.js:3692:37
fire#http://localhost/mySite/lib/jquery.js:3320:30
fireWith#http://localhost/mySite/lib/jquery.js:3450:29
fire#http://localhost/mySite/lib/jquery.js:3458:21
fire#http://localhost/mySite/lib/jquery.js:3320:30
fireWith#http://localhost/mySite/lib/jquery.js:3450:29
ready#http://localhost/mySite/lib/jquery.js:3923:13
completed#http://localhost/mySite/lib/jquery.js:3933:9
EventListener.handleEvent*#http://localhost/mySite/lib/jquery.js:3949:9
#http://localhost/mySite/lib/jquery.js:39:9
#http://localhost/mySite/lib/jquery.js:17:3
undefined
followed by:
TypeError: selectItems is undefined
and thats pointing to line 6.
if anyone has any advice I would be very much appreciative. Thank you in advance.
EDIT: A little more code:
function startTblView(defSel) {
if (defSel === true) {
setCookie('defSel', true, 7);
} else{
setCookie('defSel', false, 7);
}
saveSelected();
window.open('table.php', '_self');
defSel = getCookie('defSel');
if (defSel) {
selectItems = getDefDates();
}else {
selectItems = reGetSelected();
}
setTHead(selectItems);
}
defSel, is a boolean passed from my last page stating whether I'm doing a default view or a custom view, the custom view is passed from saveSelected();
saveSelected is a function for just saving the selected global value as a cookie so I can pull it out on the next page.
getDefDates pulls the default values for the array
reGetSelected, gets the selected array from the cookie.
I apologize for wonky naming conventions. I'm the only one working on this site and I'm just making sure the names don't overlap.
You can do this :
HTML code
<div id="datTab"></div>
JS code
var selectItems =
[ "05-26-2017", "06-02-2017", "06-09-2017",
"06-16-2017", "06-23-2017", "06-30-2017", "07-07-2017", "07-14-2017",
"07-21-2017", "07-28-2017"];
function setTHead(selectItems) {
var formatString;
$.each( selectItems, function( index, value ){
formatString = value.replace(/[^0-9/-]/g, "").toString();
$('#datTab').append("<div id='col" + index + "' class='column'>'" + value + "'</div>");
});
};
You can use $.each, its better than 'for' with javascript.
The .each() method is designed to make DOM looping constructs concise
and less error-prone. When called it iterates over the DOM elements
that are part of the jQuery object. Each time the callback runs, it is
passed the current loop iteration, beginning from 0. More importantly,
the callback is fired in the context of the current DOM element, so
the keyword this refers to the element.
I did a JsFiddle
Here.
I am currently working on a website to easily modify css properties and animate using jquery. The page will then output the code for the user to copy and paste into their work.
I am wanting to dynamically add input fields so users can enter their own parameters in "keyframes" for the animation.
I was wondering if there is a way to have a button to create the new elements and the jquery to have it operate. Currently I have tried setting a variables value to increment with the button then have a "for" loop to create the new keyframe elements.
Is there a way to append the previous keyframes with new keyframes
this is a sample of the things I need to set when creating the DOM nodes for the input fields, but the main issue I am having is incrementing the value of "i" and duplicating the code only once.
//////////TOP TEXT INPUT///////////
var newTop = document.createElement('input')
newTop.type = "text"
newTop.id ="animation_" + i + "_top" // i = 1
newTop.size="10"
newTop.value="100"
newTop.name="animation_" + i +"_top" // i = 1
newTop.textContent = "top";
var refTopSibling = document.getElementById('frame_1')
var refTopParent = refTopSibling.parentNode
refTopParent.appendChild(newTop)
//////////TOP TEXT INPUT///////////
var newLeft = document.createElement('input')
newLeft.type = "text"
newLeft.id ="animation_" + i + "_left" // i = 2
newLeft.size="10"
newLeft.value="100"
newLeft.name="animation_" + i +"_left" // i = 2
newLeft.textContent = "left";
var refTopSibling = document.getElementById("animation_" + i + "_top")
var refTopParent = refTopSibling.parentNode
refTopParent.appendChild(newLeft)
Regards,
Andrew
EDIT--------------------------
Thanks for the replies. Unfotunately it's a little large for JS fiddle. I'm only a noob so this may not be the most elegant way to do it, but I used an if statement to increment the variables current value on each press... unfortunately it's not dynamic but I have enough options to allow 11 keyframes of animation that can be dynamically added to the DOM.
function addFrame(){
var n;
if (document.getElementById('frame_1')){n=2};
if (document.getElementById('frame_2')){n=3};
if (document.getElementById('frame_3')){n=4};
if (document.getElementById('frame_4')){n=5};
if (document.getElementById('frame_5')){n=6};
if (document.getElementById('frame_6')){n=7};
if (document.getElementById('frame_7')){n=8};
if (document.getElementById('frame_8')){n=9};
if (document.getElementById('frame_9')){n=10};
if (document.getElementById('frame_10')){n=11};
//rest of the code here
}
Now to figure out a way to draw svg dynamically and animate it with user inputs ;-)
This isn't necessarily the best implementation but I believe it meets your requirements.
function SampleObject(position, i)
{
this.posString = "new" + position;
$(this[this.posString] = document.createElement("input"))
.css({ type: "text",
id: "animation_" + i + "_" + position,
size: "10" ,
value: "100" ,
name: "animation_" + i +"_" + position,
textContent: position
});
$("#frame_1").parent().append(el);
}
//Public methods
SampleObject.prototype.getInput = function()
{
return this[this.posString];
}
//Static members
SampleObject.set = [];
//Static methods
SampleObject.new = function(position);
{
this.set.push(new SampleObject(position, this.set.length + 1));
}
//Quick test
SampleObject.new("top");
jQuery rewrite aside this does three actions, albeit the last might be surplus to requirement.
1) Rather than write a new function for every position the constructor of the object takes a position string (any string would be fine but for your objective position seems apt). The string is appended to "new" to form the "new" that is used to create an object member named in accordance with the current multi-function approach in the post that stores the new input object - personally I think the member naming is redundant but I don't know the project. The object has a get method for returning the input form.
2) Using the static "Sample.new" method (which takes a position parameter) a new SampleObject which has an index value of 1 + (static member) SampleObject.set, the set variable is used to store the new objects as they are created. This might not be necessary but I imagine you'll want to interact with them later or attach event.
As for the "frame_" if statements
$("[id^=frame_]").length() + 1
Assuming that frames are always created iteratively this will return the appropriate value for n.
Let us explain the question with an example. I have a text box. The textbox (every textbox) has a property called 'value'. I want to over ride that textbox.value and comeup with and
new thing. When the text in textbox is 'ranjan' then the textbox.VALUE property returns 'ranjan'. Now I want to thus overwrite this so that when you type textbox.VALUE you get a different thing say for example, RaNjAn or say, Mr. Ranjan or whatever.
We can over ride methods using Object.PROTOTYPE property. But how can we do it for non-function objects inside object for example the 'value' property in this case.
If i need to make the question more clear, please mention.
Regards - Ranjan.
You can define custom properties for your element using Object.defineProperty
If you have a case where you need to get the value of an element as Mr. <value> for example, then this approach will be useful. Overriding standard properties may not be such a good idea.
Demo: http://jsfiddle.net/zvCGw/2/
Code:
var foo = document.getElementById('foo');
Object.defineProperty(foo, "xvalue", {
get: function() {
return 'Mr. ' + foo.value;
},
set: function(_newValue) {
foo.value = _newValue;
}
});
foo.xvalue = 'Hello';
alert(foo.xvalue);
What you are trying to do is called type augmentation. In javscript there are types of things, such as the object type, array type, etc.
You can use the prototype to augment these built in types, for example, adding a new method that can be called on any object that is of the type array:
Array.prototype.myNewMethod = function() {
//the method logic
}
Then you can call your method on any array:
[0,1,2].myNewMethod();
There is no INPUT type in JavaScript, DOM elements are classed as Objects. But you could jerry-rig something together that kind of does what you need, like this
Object.prototype.changeValue = function(el) {
if (el.tagName === "INPUT") {
return "Mr " + el.value;
}
}
var testEl = document.getElementById("test");
document.write(testEl.changeValue(testEl))
Used in conjunction with this textbox:
<input id="test" value="Dan" />
You would then get the output 'Mr Dan'
However, this is not great, it's just to illustrate the point and is just something to get you started...
I made a fiddle so you can play around with it
You can redeclare value but it will do no good ;)
This example would do that if test is a textbox
var input = document.getElementById("test");
Object.defineProperty(input, "value", {
get : function () {
return "'" + this["value"] + "'";
},
set : function (val) {
this["value"] = val;
}
});
input.value = "Hello World";
alert(input.value);
Unfortunately, "this.value" will reference the getter causing infinite recursion.
Once redefined, the original value will no longer exist so you will have crippled the element object.
At least as far as I have been able to test.
If the property you're trying to override can also be represented by an HTML attribute (e.g. an input's value), then you can use getAttribute and setAttribute.
Object.defineProperty(myInputElement, 'value', {
get: function () {
return myInputElement.getAttribute('value');
},
set: function (value) {
myInputElement.setAttribute('value', value);
}
});
Note, however, that this override itself cannot be overridden without re-implementing it.