Peculiar behaviour with jQuery/Javascript .toggleClass/.classList.toggle - javascript

First time I ask something here, I hope you people will be as helpful as ever.
I am making a script in Javascript(using some jQuery as well) that's supposed to do this:
Suppose we have a page with user posts. If someone clicks on a user's name, on one of the posts, the script will highlight every other post of the same user.
If the posts of a user are already highlighted, and we click on another user's name, in another post, then all the previously highlighted posts must return to normal state, and now the posts of the other user must be highlighted instead.
The script I have written is this.
$(function (){
$(".showall").click(function() {
var identifier = this.innerHTML;
var already = document.getElementsByClassName("highlight");
var l = already.length;
if (l) {
for (i=0; i<l; i++) {
var to_hide = already[i].id;
$("#"+to_hide).toggleClass("highlight");
}
}
var sum = document.getElementsByClassName("uid_"+identifier)
var l = sum.length;
for (i=0; i<l; i++) {
var to_show = sum[i].parentNode.parentNode.parentNode.id;
$("#"+to_show).toggleClass("highlight");
}
});
});
Let me explain a little what it does.
When the click event is triggered on one of the specified elements, it stores the user identifier, and then checks to see if there are already highlighted comments, by checking the document for the "highlight" class.
If there are highlighted comments, it's SUPPOSED TO remove the highlight class, from each and every one of them, and then, based on the user identifier, to highlight any other posts accordingly.
The problem with the script occurs in the loop inside the if(l) {} conditional, here
if (l) {
for (i=0; i<l; i++) {
var to_hide = already[i].id;
$("#"+to_hide).toggleClass("highlight");
}
}
When removing the highlight class, it does so by skipping every other post, and only does the loop for half the length.
For example, say I highlighted a user's posts. That user had 14 posts, so, all 14 of them get highlighted. Now, if I want to highlight the posts of another user, and click on his name, the script will remove the highlight from the previous posts like this:
Remove highlight from post No1
Remove highlight from post No3
Remove highlight from post No5
Remove highlight from post No7
Remove highlight from post No9
Remove highlight from post No11
Remove highlight from post No13
When I will click on another username again, it will
Remove highlight from post No2
Remove highlight from post No6
Remove highlight from post No10
Remove highlight from post No14
etc.
I do not understand why the loop behaves that way.
I have removed the line with the .toggleClass and made it so that it alerts for every element of the array, and it did so for the whole length, not half the length, without skipping elements.
It's like when I use the .toggleClass the i gets incremented by 2, and I, for the love of me, cannot understand why. I have also tried to do it with .classList.toggle, without using jQuery, and it's the same thing again.
Any help will be much appreciated.
Regards to you all.
EDIT: Forgot to add, that Chrome's console gives me this error, for the posts that the script is skipping:
Uncaught TypeError: Cannot read property 'id' of undefined.
I understand what it means, it's like it did not find a valid object to read the id property, but I do not understand why it happens.

Your code seems overly complex.
Would something like this work for your use case?
$('.user-name').click(function (e) {
e.preventDefault();
var user_id = $(this).parent().data('userid');
if (!$(this).parent().hasClass('selected')) {
$('.post.selected').removeClass('selected');
$('.post[data-userId='+ user_id +']').addClass('selected');
} else {
$('.post.selected').removeClass('selected');
}
});

Related

How do i fix the wrong integration of an automatic transfer of rows between sheets?

What I'm trying to accomplish is:
have a data input sheet called 'data' (its data is fed by a form)
script moves the information from data to sheet1/sheet2/.../sheetn (according to a string that is to be found in column 3)
script also deletes moved rows
I think the deleteRow command works fine, i suspect the culprit being the detection of the string in the array.
I've already used the search a lot, tried a few codes and I've identified this as the most probable candidate (its by cooper), as it's almost doing what i need it to do.
I tried logging a bit, but unfortunately i dont know too much about coding yet. Currently im learning by trial and error.
If i log for vals[i][2] i only get 1 string, instead of a few from my example input.
When i set only one targetsheet (sh1) and target-term it works. but when i extend it it doesnt work anymore.
{
var ss=SpreadsheetApp.getActive();
var sh0=ss.getSheetByName('Data');
var rg0=sh0.getDataRange();
var sh1=ss.getSheetByName('Applesheet');
var sh2=ss.getSheetByName('Banana');
var sh3=ss.getSheetByName('Cherry');
var vals=rg0.getValues();
Logger.log(vals)
for(var i=vals.length-1;i>0;i--)
{
if(vals[i][2]=='Apple')
Logger.log("PV Abfrage -", vals[i][2])
{
sh1.appendRow(vals[i]);
sh0.deleteRow(i+1);
}
if(vals[i][2]=='Banana') //also tried with else if here
{
sh2.appendRow(vals[i]);
sh0.deleteRow(i+1);
}
if(vals[i][2]=='Cherry')
{
sh3.appendRow(vals[i]);
sh0.deleteRow(i+1);
}
}
}
My code moves rows that dont contain any of the terms.
It's also supposed to only move rows that contain this term, but its doing so super unrealiably.
I think all rows get appended to Applesheet, rows that contain banana are moved to banana but the ones with cherry wont.
Im definitely not experienced enough to judge, but this code seems a bit unreliable, because even my test version with just one if fails to perform the way i want it to.
Issue:
Your first if statement is forced to return true by the Logger.log() you've included between if and {. As soon as you remove it, your code functions exactly as you're expecting.
Example:
If we run the following script:
var check = ['Apple', 'Pear', 'Fruit'];
for (i = 0; i < check.length; i++) {
if (check[i] === 'Apple') {
console.log('Found!');
}
}
We're looping through an array, and logging "Found!" for every time the item in the array is found. This is the same way your script works. It works as expected, "Apple" is only found once in the array, so the log looks like this:
Found!
As soon as we put a log between the if and the {, like so:
var check = ['Apple', 'Pear', 'Fruit'];
for (i = 0; i < check.length; i++) {
if (check[i] === 'Apple')
console.log("Oops!")
{
console.log('Found!');
}
}
We get the following:
Oops!
Found!
Found!
Found!
Summary:
Make sure to only include your conditions for the if statement between your if and {, adding anything else can return false positives like you've experienced today.
Reference:
JavaScript if Statements

Attempting to make nested questions appear dynamically... C# ASP.Net Database First,

Idea for making elements visible or invisible:
So… how the loop works right now is it for each category, it loops through each question in each category.
The idea is: Each question can be answered yes or no, and then for each question answered yes, there can be up to 5 dates added.
What I want to do:
-If yes, first date appears:
-If the first date is answered, then a second question appears, and so on.
These questions are stored in a sql server like so:
I want only the inner loop to have this ability to be visible or invisible..
My thought is to do a nested loop and check check on each element.
//Psuedo code
//For each first question which has 5 sub questions that are all set to hidden:
var questioncount = (count of the first questions)
for(int i = 0; i<questioncount; i++){
// set first variable to hold the first questions object.
var element(‘#questionElement’ + i);
// set firstElement to selected answer
var isAnsweredYes = firstElement.(‘Yes’);
for int j = 0; i<subQuestionCount; j++)
if (isAnsweredYes == True){
// jQuery selector to get an element
var query = $('#element' + j);
// check if element is Visible
var isVisible = query.is(':visible');
if (isVisible === true) {
// element is Visible
// do nothing
} else {
// element is Hidden
query.show();
}
else
{
//do nothing
}
}
}
Does my logic seem forward? or can anyone advise me in a better way?
I would use a button that says "Add another date", which is displayed under the last date field as soon as at least one is visible. That way you won't have to decide on a certain number (e.g. 5) as the maximum, plus I think it's a rather intuitive way of extending a form.
On each press of the button, create new input controls; be it in javascript or server side, it makes no real difference.

I attached an onClick prompt to an SVG image, but i cant get the prompt to run a jQuery if else statement

I'm making an SVG map of the US most of it is done so far, its all down to a simple if else statement so that i can finish. The goal is if i click on a state (i have the path and id for every state) a prompt will pop up asking for state name. The jQuery code is then supposed to fill the state green if answer i put into the prompt is correct, and red if incorrect. It does fill red when i enter something into the prompt, however it does this every time, even when the prompt is correct. How can i fix this please i need a quick answer by today.
Here is the jsfiddle https://jsfiddle.net/vnqcyu90/
jQuery(function($) {
$('path').click(function() {
prompt("Enter State Initials")
if ($('path id') == prompt) {
this.style.fill = "green";
} else {
this.style.fill = "red";
}
});
});
that's the specific line of code causing me issues, it both adds the onclick function to the SVG map, as well as handle the if else statement related to the prompt asking the name of the state which in my case is the path id. (This code is jQuery 1.7.1)
There are several problems with your code.
First, you are not assigning the result of Window.prompt() to anything. You need to do:
var prompt = window.prompt("Enter State Initials");
The next problem is your jQuery selector
$('path id')
jQuery selectors return a list of elements that match your selector string. In this case, you are asking it to return all elements named "id" (ie. <id>) who have an ancestor <path> element.
If you want to check the id value of the path you click on, then what you need to do is:
$(this).get(0).id
$(this) turns the clicked element into a jQuery object. The get(0) gets the first element of the jQuery object (remember jQuery selectors always return a list). In this case however, there will only ever be one element in the list.
And you get read the id attribute of the element simply by referencing the id property of the element.
So your final code would look like:
var prompt = window.prompt("Enter State Initials")
if ($(this).get(0).id == prompt) {
this.style.fill = "green";
} else {
this.style.fill = "red";
}
Since all your state ids are uppercase, you'll probably also want to convert the text people type in. For example:
var prompt = window.prompt("Enter State Initials").toUpperCase();
Updated fiddle

Generate multiple checkboxes from Javascript array?

My jsfiddle will help explain things better than I ever can >< http://jsfiddle.net/L65QD/17/
I've got two select boxes, when you select something from the first select it enables the second. I have quite a few arrays that I'm using as sort of a fake database.
What I need to happen is that depending on what is selected in profile_select it needs to generate checkboxes for every PRIVILEGE_CODE it has, however the checkboxes must be generated with SEC_PRIVILEGES.Name next to them instead of the actual PRIVILEGE_CODE and they must be generated in the correct DIV. Since it's so hard to explain I made a JSFiddle which just about summarizes it http://jsfiddle.net/L65QD/17/
If my instructions aren't clear:
Depending on what profile is selected in the PROFILE_SELECTION
Needs to generate some checkboxes based on what PRIVILEGE_PROFILES.PRIVILEGE_CODES it has
However the checkboxes must have the name from SEC_PRIVILEGES next to them instead of the code, so PRIVILEGE_CODES = Unique_Code
Checkboxes are generated in either the DA div or the MR div based on what Group_Code they have in SEC_PRIVILEGES (this bit really confuses me, can you make it so a DIV ID can be equal to something from an array?) However to generate them in DA or MR it can't really be an IF because my fiddle is just an example and I'd actually have about 30 different codes so I couldn't do 30 IF statements.
This is the method I was experimenting with but it doesn't really make sense and is probably not even close to being on the right lines:
$(document).on('change', '#select_profile', function () {
var Select = $("#select_profile option:selected").text();
$("#apps").html;
for (var i = 0; i < SEC_Privileges.length; i++) {
if (SEC_Privileges[i].Unique_Code == //something?) {
$('#DA').html("<b>lol</b>");
}
}
});
So that's pretty simple:
Correct this fatal error: Array literals are written in square bracket notation ([], not ()). When you log the PRIVILEGE_PROFILE[0].PRIVILEGE_CODE you'll see only the first code is logged as the key's value.
Building the function: Consider what you need:
When a user changes company, all checkboxes must be reset
When a user changes profile, all checkboxes must be reset, then changed accordingly
When 'None' is selected in either dropdown, all checkboxes must be reset
Result: http://jsfiddle.net/kevinvanlierde/L65QD/19/
Some conventions:
Please choose one naming convention and stick with it. The more common ones are lowercase_underscore or CamelCase. You can opt for uppercase, but don't mix them (easier readability). I've had several errors just because I wrote the names incorrectly.
Declare your variables at the start of your function, assign them further on.
Also want to add that if I were to have control over the object's structure, I would probably opt for a more hierarchical tree/ JSON-like structure, eg instead of your current object, do:
var SEC_Privileges = {
'DA': {
'name': 'Dispatch App',
'accesses': {
'DAAccess': 'Access',
'DASuper': 'Supervisor'
}
},
'MR': {
'name': 'MyRoster',
'accesses': {
'MRAccess': 'Access',
'MRSuper': 'Supervisor'
}
}
}
Because the object keys are themselves values, you can use them to build your UI, eg to get the full name of your MRAccess you could do something like SEC_Privileges.MR.name + SEC_Privileges.MR.accesses.MRAccess to get MyRoster Access
There is different ways to approach this but the amount of Privileges would always be the same?. Depending on what your SEC_privileges is if its JSON array then you could loop through that array and access the code and the description. You would then want to validate the selected privileges again the whole set and say something like:
var array = ('one','two','three');
if($.inArray(SEC_privileges[i].Unique_code, array))
{
$('#DA').html("<input type='checkbox' id='"+i+"' value='"+SEC_privileges[i].Unique_code+"' checked/>"+SEC_privileges[i].Unique_desc);
}
else
{
$('#DA').html("<input type='checkbox' id='"+i+"' value='"+SEC_privileges[i].Unique_code+"'/>"+SEC_privileges[i].Unique_desc);
}
A ticked value is done by adding the word checked as part of the html input object. Like illustrated above

How can I remove blank lines in an array generated that show in a dropdown

I have a dropdown that is generated using javascript and html. I have some code which I will post below that loops through this list and should potentially remove any blank lines found but is not working. "$maxfield1rows" has a value of 7, what I am saying is that if the value is a blank (=='') then remove it. I used removeChild but this doesn't seem to work, I also tried splice, I think filter can work but am not sure. I tried the disabled=true but that just makes them disabled and unselectable. Can someone please help?
for(index=1; index<$maxfield1rows; index++) {
if(document.pickDivision.field1.options[index].value=='') {
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[index]);
}
}
Updated below, I'm using $maxfield1rows since that is the amount of maximum number of rows the the loop goes through, also by change I meant that there is an onchange event that gets triggered when the user selects a different option in the dropdown menu, so depending on the option selected the output for field1 changes, sometimes there are 5 values that show and sometimes just 1:
for(index=$maxfield1rows-1; index>=0; index--) {
alert(document.pickDivision.field1.options[index]);
if(document.pickDivision.field1.options[index].value==''){
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[index]);
document.pickDivision.field1.options[index].disabled=true;
}
else{
document.pickDivision.field1.options[index].disabled=false;
}
}
To expand upon my comment, I think the issue is that you are looping forwards through the options array. I am surprised that no error is being thrown when you try to do this. You should loop backwards through the collection to keep from skipping an item.
JS Fiddle demonstrating the error. In the example, items 1 and 2 are blank and item 3 is not.
These built in collections are changed each time your add/remove an item. Using the example in the fiddle, my array changes from [1,2,3] to [2,3] to error no item at index 2.
Looping backwards, my collection takes this change: [1,2,3] to [1,3] to [3].
Here is the code with comments explaining what each part of the for loop is used for and why. You can use a while loop if you prefer too.
//options.length - 1 because arrays are 0 based
//i >= 0 because you don't want to use a negative index on an array
//i-- to loop backwards
for(var i = document.pickDivision.field1.options.length - 1; i >= 0; i--) {
//Is this an empty item
if(document.pickDivision.field1.options[i].value == '') {
//Remove the empty item
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[i]);
}
}
UPDATE
With the newly updated code you posted, you are attempting to access an option element after it has been removed. From the looks of the line, you don't need it anymore as you are already removing the element. If you do still want to disable the element before removing it, move that line above the other line (see comment in code).
for(index=$maxfield1rows-1; index>=0; index--) {
alert(document.pickDivision.field1.options[index]);
if(document.pickDivision.field1.options[index].value==''){
document.pickDivision.field1.removeChild(document.pickDivision.field1.options[index]);
//This line is causing the issue; move it above the previous line or remove it
document.pickDivision.field1.options[index].disabled=true;
}
else{
document.pickDivision.field1.options[index].disabled=false;
}
}
UPDATE 2
Per the question in the comments, when you change the number of options to 6, your code breaks. This is because you are using the hard coded PHP value $maxfield1rows. Since you already know the name of the form and the name of the field in the form, I would recommend you use the length of the options collection in your for loop rather than this variable. This will make sure that no matter how many option elements there are (1, 10, 1000), you will always loop through the entire collection.
for(var i = document.pickDivision.field1.options.length - 1; i >= 0; i--) {

Categories

Resources