1. Advertising
    y u no do it?

    Advertising (learn more)

    Advertise virtually anything here, with CPM banner ads, CPM email ads and CPC contextual links. You can target relevant areas of the site and show ads based on geographical location of the user if you wish.

    Starts at just $1 per CPM or $0.10 per CPC.

Why? Click event works programmatically, but not with mouse.

Discussion in 'HTML & Website Design' started by SoftLink, May 25, 2022.

  1. #1
    It's difficult to show you the all the code but maybe you know something about it.
    I create a click event like shown below:
    If after addEventListener I add divSel.click() the click works.
    BUT if I click the button with the mouse it does not work.

    Someone please tell my why????
    SEMrush
    
    divDataSel = document.createElement("div");
         divBlock.appendChild(divDataSel);    
         divSel = document.createElement("div");
         divSel.className = "Button1aSm";
         if(oBlockRec.Data.nChtData == 1) divSel.classList.add("Button1aSmOn");    
         divSel.innerHTML = "Count";
         divDataSel.appendChild(divSel);
         divSel.addEventListener("click", (evt) => { setStatsAnlyBlockDataCht(oBlockRec.BlockIdx, 1) });
        
         if(is_numeric(arData0.Avg) || arData0.Avg == "n/a") {
           divSel = document.createElement("div");
           divSel.className = "Button1aSm";
           if(oBlockRec.Data.nChtData == 2) divSel.classList.add("Button1aSmOn");    
           divSel.innerHTML = "Average";
           divDataSel.appendChild(divSel);
           divSel.addEventListener("click", (evt) => { setStatsAnlyBlockDataCht(oBlockRec.BlockIdx, 2) });
         }
         if(is_numeric(arData0.Pcnt)) {
           divSel = document.createElement("div");
           divSel.className = "Button1aSm";
           if(oBlockRec.Data.nChtData == 3) divSel.classList.add("Button1aSmOn");    
           divSel.innerHTML = "Percent";
           divDataSel.appendChild(divSel);
           divSel.addEventListener("click", (evt) => { setStatsAnlyBlockDataCht(oBlockRec.BlockIdx, 3) });
         }
         if(is_numeric(arData0.Snt)) {      
           divSel = document.createElement("div");
           divSel.className = "Button1aSm";
           if(oBlockRec.Data.nChtData == 4) divSel.classList.add("Button1aSmOn");    
           divSel.innerHTML = "Sentiment Avg.";
           divDataSel.appendChild(divSel);
           divSel.addEventListener("click", (evt) => { setStatsAnlyBlockDataCht(oBlockRec.BlockIdx, 4) });
         }
    
    Code (markup):
     
    SoftLink, May 25, 2022 IP
    SEMrush
  2. hdewantara

    hdewantara Well-Known Member

    Messages:
    518
    Likes Received:
    46
    Best Answers:
    23
    Trophy Points:
    130
    #2
    Hi SoftLink,
    I could only guess: perhaps there's an element in front of divSel which blocks mouse clicks from reaching divSel.
    Have an URL link to demo page that may help me test?
     
    hdewantara, May 25, 2022 IP
  3. SoftLink

    SoftLink Greenhorn

    Messages:
    48
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    23
    #3
    Thanks for responding.
    Nope, there's nothing over it.
    I can't show the page because it's login, proprietary, etc . . . Sorry.
    A report table follows the buttons (not 'over' them, 'below' them).
    If I don't include the table the buttons work fine.
    I tried adding the buttons after I added the table.
    This time the buttons didn't show up at all.
    I did console.log(divDataSel.innerHTML). The buttons were in the html.
    Just FYI - the css class for the buttons is standard for this app. Hundreds of buttons exist with this class.
    They all show up.
    I added a red border to divDataSel and the browser displayed a flat red line just above the table.

    I finally rewrote the code using a string variable, html instead of creating elements.
    I used .innerHTML to add the code to the page.
    After everything was drawn I added the .addEventListener('click' ...) code.

    Now everything looks just like it did, like it's supposed to and the click events work just fine.
    I hate Javascript because it's completely amateur. I'm tired of endlessly having to find workarounds for a bad programming language.

    Thanks again for responding.

    StatsAnlyButtons.png
     
    SoftLink, May 30, 2022 IP
  4. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,615
    Likes Received:
    1,964
    Best Answers:
    248
    Trophy Points:
    515
    #4
    1) Unless your intent is to flip the bird at non-mouse non-touch users, don't set onclick on a DIV. It's not keyboard navigable and may report the wrong even.

    2) Failing to declare "var" or scoping like "let/const" is probably a good chunk of your problems.

    3) Don't use innerHTML unless you actually have markup involved.

    4) Object.assign is your friend. As are functions. Much less function expressions now providing us with scope isolation thanks to let/const.

    In general, I'd say your gripe about JavaScript being a "toy" is that you've not learned enough about JavaScript, or you haven't embraced what makes JavaScript powerful.

    Guessing wildly but:

    
    { // scope isolation
    
    	const
    	
    		divDataSel = divBlock.appendChild(document.createElement("div")),
    		
    		onclick = (event) => {
    			setStatsAnlyBlockDataCht(oBlockRec.BlockIdx, event.currentTarget.value);
    		}, // onclick
    		
    		makeButton = (textContent, value) => {
    			let className = "Button1aSm" + (
    				oBlockRec.Data.nChtData === value ?
    				"Button1aSmOn" :
    				""
    			);
    			divDataSel.appendChild(
    				Object.assign(
    					document.createElement("button"),
    					{
    						className,
    						onclick,
    						textContent,
    						type : "button", // so we don't have to event.preventDefault()
    						value
    					}
    				)
    			);
    		}; // makebutton
    
    		
    	makeButton("Count", 1);
    					
    	if (
    		is_numeric(arData0.Avg) ||
    		arData0.Avg == "n/a"
    	) makeButton("Average", 2);
    
    	if (is_numeric(arData0.Pcnt)) makeButton("Percent", 3);
    
    	if (is_numeric(arData0.Snt)) makeButton("Sentiment Avg.", 4);
    
    } // scope isolation
    
    Code (markup):
    Is more likely how it should be handled, though I'm concerned about hwo you seem to be trying to access some sort of global inside the event handler instead of storing the related information in a useful location like on the element. That bespeaks not only failing to grasp the simplicity of JavaScript, but also not understanding how to use HTML properly either.

    Much less those variable and class names make me wanna vomit.
     
    deathshadow, Jun 8, 2022 IP
  5. SoftLink

    SoftLink Greenhorn

    Messages:
    48
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    23
    #5
    Thanks for the response. I've only been programming Javascript and HTML for about 25 years so, maybe not enough experience; education.
    The code is in a function and all of the vars are scoped within the function. I just left that out of the post.

    I'm not sure what you mean by this: "you seem to be trying to access some sort of global inside the event handler". Are you referring to oBlockRec?
    That's a var in the function that this code is in. I suppose I could store the BlockIdx in a dataset attribute or something.
    The code blocks inside the addEventListener calls did have access the oBlockRec var so I don't see the problem with it.

    This code doesn't work. It doesn't have access to oBlockRec and event.currentTarget.value is not the parameter.
    It's an integer indicating the numeric value to display (cnt, avg, pcnt or sntavg). I suppose I could have put that into a dataset attribute too but - why?
    onclick = (event) => {
    setStatsAnlyBlockDataCht(oBlockRec.BlockIdx, event.currentTarget.value);
    }, // onclick

    I'd say YEA, wild guess.

    I have another function for a different report that uses the *exact* same code (which I don't usually do) and it works fine.

    This was definitely a Javascript problem. I rewrote the whole thing using a string var and innerHTML. I added the addEventListener clicks after I set the html.
    Now everything works fine. All of the resultant html is in the exact same place. The click events work now.

    Your use of Object.assign is interesting. I'm not sure why you're using it but I'll investigate it a bit.
    I'm always interested in learning so I appreciate your response.
    Thanks again.
     
    SoftLink, Jun 9, 2022 IP
  6. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,615
    Likes Received:
    1,964
    Best Answers:
    248
    Trophy Points:
    515
    #6
    Hah, I'd say "education' isn't the problem so much as JavaScript is a moving target. Your code looks 20 years out of date. Happens to the best of us. The changes the past... six years alone have been jaw-dropping. This ain't your grandpa's JavaScript no more. Especially since most of us have kicked support for browser versions more than six years old to the curb.

    I have to be careful because with 40+ years of programming and about 25 years of working with web languages, I can easily fall into old habits that are not necessarily the best practice. Like using var or failing to manage scope in a secure manner.

    I don't necessarily agree with the "stop using var altogether" crowd as there are a lot of cases where what it does is what I need, but let/const giving us block level scoping -- eliminating the need for IIFE in a lot of cases -- is a huge improvement. I was actually very skeptical of let/const when they were introduced until I stumbled on how a simple {} can replace IIFE entirely!

    Yeah, that seems like data that might be better attached to the element itself via dataList, but I'm not sure. I'd have to see more of the code.

    Ooh, be VERY careful with that. If what you plug into InnerHTML is user generated, you might have just opened up an XSS exploit. Alongside the performance issues, the security woes innerHTML brings to the table is why we REALLY were supposed to not use it to add content to pages unless you're VERY certain of the source.

    In all but a handful of usage cases like building SPA, innerHTML is an outmoded relic to be avoided.

    Object.assign is cute because it lets you take the properties of one object and assign them to another.

    The syntax:
    Object.assign(targetObject, ...sourceObjects)

    Is handy so you're not constantly saying the same target over and over again. Likewise since object literals will take the value and name off a variable directly, you can state things a lot simpler / faster. Add to this that Object.assign returns the targetObject as it's value, you can nest them.

    Basically this:

    
    divDataSel.appendChild(
    	Object.assign(
    		document.createElement("button"),
    		{
    			className,
    			onclick,
    			textContent,
    			type : "button",
    			value
    		}
    	)
    );
    
    Code (markup):
    Is functionally identical to:

    
    {
    	let button = document.createElement("button");
    	button.className = className;
    	button.onclick = onclick;
    	button.textContent = textContent;
    	button.type = "button";
    	button.value = value;
    	divDataSet.appendChild(button);
    }
    
    Code (markup):
    The outer {} is so that the "let button" variable doesn't bleed into the parent scope. I find the former syntax clearer/easier to work with and because we're passing result as arguments we aren't wasting an extra "variable for nothing".

    Also note since we literally just made the "button" we can directly assign onclick instead of addEventListener and get the same behavior. Something normally frowned on since other things might add their own listeners... but they would do so later. We literally just made the element so nothing has had a chance to pull that stunt yet!

    I also use appendChild instead of append as the latter doesn't return the element that was appended. If you're adding one thing only, "appendChild" is superior in that way. If you want to append a bunch of elements and/or text, then append wins.
     
    deathshadow, Jun 9, 2022 IP
  7. SoftLink

    SoftLink Greenhorn

    Messages:
    48
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    23
    #7
    Thanks for your response, again.
    As far as const/let go, I use const if it's not going to change after I declare/instantiate it. Otherwise I use var unless I'm in an interior code block and want to keep it within that scope - then I use let.
    I still don't get the big deal about let. My primary concern is consumption of memory. Scope kills the variable when I don't need it anymore. I suppose there is something to be said for security as well.
    Again I use let if it's to be used in a small code block, most often a while or for loop.

    I don't get this:
    
    {
    Object.assign(
    document.createElement("button"),
    {
    className,
    onclick,
    textContent,
    type : "button",
    value
    }
    )
    }
    
    Code (markup):
    VS
    
    {
    let button = document.createElement("button");
    button.className = className;
    button.onclick = onclick;
    button.textContent = textContent;
    button.type = "button";
    button.value = value;
    divDataSet.appendChild(button);
    }
    
    Code (markup):
    In the first block those vars have to be created before you can assign them anyway so I don't get the point.
    In the second, the attributes are named so Javascript knows what var to put into what attribute.
    In the first block how does Javascript know what to put into what attribute? Is it the *name* of the variable, the position in the list or . . . ?

    oBlockRec is used throughout the interface and is actually one object in an array (thus BlockIdx). It's a whole bunch of data taken from the server.
    I think it's too much to try to store in an html element and I don't see any point in doing it. I would have to store it in a lot of elements, all of which use that data.

    The innerHTML I used is not derived from user input and was the only way I could wrangle Javascript into a.) actually displaying the html and b.) triggering the click event.
    Note: in one variation using document.createElement when I did console.log(divDataSet.innerHTML) the html was there but the browser didn't display it.
    Also again, the click event worked if I triggered it programmatically, just not with the mouse. No elements exist over the buttons on the z axis.
    That's not the first time that's happened to me.

    You're right about not using click.
    I need to change that to pointerup. I usually do that but it slipped past me here. I'll fix that.
    In that particular instance I don't see using key events. This is a report and the keyboard isn't used much here.
    Thanks for the tip!

    I'm sure Object.assign will come in handy at some point.
    Thanks again for your help.

    I just have to say though, I *hate* this: "I'll kill you and your dreams tonight, begin new life. Bleed your death upon me, let your bloodline feed my youth." :)
     
    SoftLink, Jun 9, 2022 IP
  8. deathshadow

    deathshadow Acclaimed Member

    Messages:
    9,615
    Likes Received:
    1,964
    Best Answers:
    248
    Trophy Points:
    515
    #8
    (re object literals)

    I think you don't grasp how object literals work. Know how you can declare an object like this?

    let myObj = {
      "className" : className,
       "onclick" : onclick,
       "type" : "button"
    };
    Code (markup):
    If the variable name is the same as your desired class property name, just say the variable name. This is functionally identical to the above:

    
    let myObj = {
      className,
      onclick,
      type : "button"
    }
    
    Code (markup):
    And because we assign it to an object literal, we can pass that to Object.assign to put it on the object.

    Which beats the piss out of saying "button." a half dozen times.

    Think about it inside a function, where you're passing arguments. Or when you can share the same event handler for different data. It starts to really save you a lot of work. More so if you're passing around objects instead of individual variables.

    As I said I'm guessing wildly without seeing the whole picture. It's just that what you're doing looks like the type of stuff I -- as an accessibility and efficiency consultant -- am constantly ripping out of websites and web crapplications. It looks like a lot of client side scripting which is in and of itself an accessibility violation when used that way.

    That to me would mean something was just really wrong with one of your globals and/or how you were trying to work on the DOM. Again your original code feels 20+ years out of date, and it's not like the code I provided was written as a 1:1 drop-in as there were a lot of other changes upstream that would have had to be made.

    Did you release execution before trying to access it?

    1) it's not actually on the DOM until you append / appendChild

    2) it's not in innerHTML until you release execution or perform an operation that does a reflow.

    And those are actually reasons to do it on the DOM with createElement and append/appendChild. "It's not a bug, it's a feature!". Which is why if you want to further manipulate you store the variable... and why your events should grab data from event.currentTarget not globals.

    But then the way people slop unique generated ID's on things to avoid walking the DOM, or pass data that isn't needed around, or do the "state based" rubbish rather than just leveraging the DOM... it'
    s hardly a shock so many simple tasks end up with mountains of "data" where 99% of it isn't needed.

    Not sure what you even mean by "programmatically", but that is likely an indication that something elsewhere in your code is rubbish, possibly the HTML. If your HTML is as out of date as your markup, "Well there's your problem.".

    Hell, one unclosed LABEL can wreak havoc on focus.

    So... not a Slayer fan? Or Uke Group? I love Sarah and Rob's Uke group cover. Surprised you didn't comment on who my avatar is... Let's just say he's got balls. BOY!

    So grab your uke and bring a friend too, 'cause it's time for Sunday Uke group.

     
    Last edited: Jun 9, 2022
    deathshadow, Jun 9, 2022 IP
  9. SoftLink

    SoftLink Greenhorn

    Messages:
    48
    Likes Received:
    4
    Best Answers:
    0
    Trophy Points:
    23
    #9
    Ah, object literals - I see, it's the variable name. Thanks.
    I'm not sure what you mean by this: "release execution or perform an operation that does a reflow".
    With that code I wasn't using innerHTML, I was using document.createElement and appendChild.
    If it was an error in my code I really wish I could find out what was wrong. As I said, it's not the first time it's happened.
    For me it's not academic though, I'm trying to get an app developed as fast as I can.

    Programmatically just means divSel.click().

    Ah, Slayer. Ironically I'm a shred lead guitarist. I've played since age 5, lead since 13 - spend way too many hours practicing - still.
    I like Satch, Vai, Malmsteen (I hate Malmsteen but what a guitarist!), John Petrucci, etc.
    I taught guitar for awhile. It was no fun, like babysitting children.
    My hair used to be half way down my back.
    Naw, I never did like Metal, gore - stuff like that. I like Hendrix, Zep, older stuff.
    I've got a friend who shreds on a mandolin (a double stringed uke) though.
     
    SoftLink, Jun 10, 2022 IP