So I got a little codepen. Everything works so far except a little thing. I got a <h1> and an <input>. When I type something in the text input, its value should get passed to the <h1> in realtime.
I tried to do that with a keyup function:
$('input[name=titleInput]').keyup(function(){
$('#title').text(this.value);
});
Something happens, but not what I want.When I type something in the text input, then delete it (with backspace) and re-enter something, only the first character gets passed to the title.Try it out on my codepen. Maybe it's just a stupid mistake of mine, but to me this behaviour is pretty weird.Thanks for your help in advance!EDIT:I am using text-fill-color, which may causes the problem.EDIT 2:A friend of mine tested it. It worked for her. She's using Chrome and the same version as me (58.0.3029.110 (official build) (64-Bit)).
Chrome does not update the content correctly. Such kind of bugs can always happen if you use vendor prefixed css properties, so you should avoid those.
You could hide the container before update, and then show it again with a timeout. This will trigger an update, but would also result in flickering.
$('input[name=titleInput]').keyup(function(){
$('.clipped').hide()
$('#title').text(this.value);
setTimeout(function() {
$('.clipped').show();
})
});
EDIT An alternative might be to use background-clip on the text and provide the inverted image yourself, but I right now don't have time to test that.
EDIT2 Based on the test of #TobiasGlaus the following code does solve the problem without flickering:
$('input[name=titleInput]').keyup(function(){
$('.clipped').hide().show(0)
$('#title').text(this.value);
});
This seems to be different to $('.clipped').hide().show() most likely it starts an animation with duration 0 and uses requestAnimationFrame which also triggers a redraw. To not relay on this jQuery behaviour, the code should be written as:
$('input[name=titleInput]').keyup(function(){
if( window.requestAnimationFrame ) {
$('.clipped').hide();
}
$('#title').text(this.value);
if( window.requestAnimationFrame ) {
window.requestAnimationFrame(function() {
$('.clipped').show();
})
}
});
i'd use the following lines:
$('input[name=titleInput]').bind('keypress paste', function() {
setTimeout(function() {
var value = $('input[name=titleInput]').val();
$('#title').text(value);
}, 0)
});
This will listen to the paste / keypress events, and will update the value on change.
Related
I came across a situation were a button event handler calls a function, that may take a couple seconds to complete depending on the input. Once the function completes, the output will show up in a grid.
The function is completely client side. Right before the function is running I add a css class to the grid wrapper div that basically just shows a 'loading' gif/animation.
This works fine in Chrome, but not in Firefox and IE 11.
Below is an oversimplified version of how I achieve this with javascript setTimeout 0.
$('#calc').on('click', function(){
$('#container').addClass('loading');
calculate(10, function(res){
$('#result').text(res);
$('#container').removeClass('loading');
});
});
//represents my long running function
function fib(n) {
if(n<2) {
return n;
}
return fib(n-2) + fib(n-1);
}
//will be called by click handler
function calculate(n,cb) {
setTimeout(function(){
var result = fib(n);
return cb(result);
},0)
}
As you can see I use setTimeout 0 in calculate(n,cb) to give the browser the ability to show the 'loading' animation before the function starts and then remove it when it is done.
However, this does not work in Firefox.
What are some other options for me to achieve what I am trying to do?
I am using jQuery here, but the actual project I am working on is using Angular5. But the idea should be the same.
Here is a jsFiddle to show what I am trying to do. Using the loading animation by Mattln4D (thanks)
https://jsfiddle.net/alabianc/qL5zggh7/
If you want to see some actual good result, run it with 40 as an input in calculate, but no more than that!
I appreciate any help!
I think if you set the timeout = 0, it is so fast to browser can show the loading animation. When I try to change timeout = 10 or 100, I can see the loading animation show on both of chrome, ff.
I'm trying to limit the user's ability to click on an object to a certain time limit. I looked around and found that apparently, setTimeout() is the correct function to use for this type of thing. I've applied the function to my code, but its not working. I'm thinking/know now that the problem is that the setTimeout in my code isn't limiting the actual click event, which I need to do. Here is a snippet of my click code:
function clickRun(event) {
var $objectVersion = correspondingObject(event.target.id);
if (isAnyVisible() == false) { // none open
$objectVersion.makeVisible();
} else if (isAnyVisible() && $objectVersion.isVisible()) { //click already open div
$objectVersion.makeInvisible();
} else if (isAnyVisible() && $objectVersion.isVisible()==false) { //different div open
searchAndDestroy();
$objectVersion.delay(600).makeVisible();
};
};
$('.ChartLink').click(function(event) {
setTimeout(clickRun(event),5000);
});
I've also created a JSFiddle to represent what I'm talking about: http://jsfiddle.net/FHC7s/
Is there a way to achieve limiting the actual click detection on the page?
I think the easiest way to do it is to keep track of the time of the previous click and if the current click is too soon after that, then don't do anything:
onClick = function(){
if(new Date().getTime() - lastCheck < MIN_CLICK_SPACING) return;
}
Have a look at this JSFiddle, I've set it up so you can have the button disable itself for time duration after detecting a click. Just make sure to remember how your closures are operating with your setTimeouts.
Your code contains an error... your line should be
setTimeout(function(){clickRun(event)},5000);
but even then I don't think that's exactly what you're looking for; that code will "delay" the click by 5 seconds, not actually prevent more clicks. If your true intent is to ignore all clicks after a certain amount of time, then I would go with mowwalker's answer; there's no way to stop the clicks, but you can check to see if you should honor them or not.
I'm writing a simple text-base game in my free time. It's called TARDIS flight (Doctor Who!) and I'm working on the main menu.
So I'm using a function, addMainMenuListeners, to add all the event listeners with addEventListener, after I set the innerHTML of the main menu.
Everything works fine, until the point where I go back to the main menu from one of the submenus. Then, I found that the buttons don't work anymore.I'm calling addMainMenuListeners after I set the innerHTML, but even though I do it, and I do it in the console, and I check, there is no event.
Code:
In my main javascript file:
function addMainMenuListeners()
{
if($("start")) $("start").addEventListener("click", startGame);
if($("instructions")) $("instructions").addEventListener("click", instructions);
if($("settings")) $("settings").addEventListener("click", settings);
if($("back")) $("back").addEventListener("click", resetMainMenu);
if($("volume")) $("volume").addEventListener("change", function(){saveAndChangeVolume($("volume").value);});
}
function instructions()
{
$("mainmenu").innerHTML = "<h1>Instructions</h1><p>Fly your TARDIS through the time vortex using the console. Make sure that you use the correct materialization codes. Try to keep the time-space coordinates close to the values of the ones given. AND DON'T CREATE PARADOXES, WHATEVER YOU DO!</p><button id='back'>Back</button>";
addMainMenuListeners();
return true;
}
function settings()
{
$("mainmenu").innerHTML = "<h1>Volume</h1><span>1</span><input type='range' id='volume' min='1' max='100' /><span>100</span><br><button id='back'>Back</button>";
addMainMenuListeners();
loadVolume();
return true;
}
function resetMainMenu()
{
$("mainmenu").innerHTML = "<h1>TARDIS Flight</h1><button id='start'>Start!</button><button id='instructions'>Instructions</button><button id='settings'>Settings</button>";
addMainMenuListeners();
return true;
}
And in my HTML file:
<div id="mainmenu">
<h1>TARDIS Flight</h1>
<button id="start">Start!</button>
<button id="instructions">Instructions</button>
<button id="settings">Settings</button>
</div>
If you need any clarification, just ask.
EDIT: Evidentally, nobody got what I meant. I was readding the event listeners after doing the innerHTML, as you can see from the code. I simply cannot see the event being added, the function is firing but not adding the event.
Also, I am using a custom $ function, just a return document.getElementById(id) sort of function.
Check to see if your $() uses any caching. If it caches old references to elements then when innerHTML is set the $("id") will return a reference to an invalid reference.
[edit] The references are more likely valid even though they are no longer visible in the HTML DOM. So modifying the detached elements works but it doesn't do any good since they are detached from the DOM.
Sukima psychic ability's catched the main problem: your custom $ function (to replace document.getElementById) used a caching mechanism.
After some testing (out of personal curiosity) it turned out that as long as you have some reference to an element, the element is still accessible, even after elm.parentNode.removeChild or a full elm.parentNode.innerHTML rewrite (at least, in FF).
In other words: the events WERE added, every time, just to the wrong/old/previous elements instead of the new ones. Otherwise there would also have been errors that the elements didn't exist and thus didn't have an addEventListener method..
See this crude test-fiddle for proof: http://jsfiddle.net/G28Lu/
I toyed around with a $ function (as you haven't posted yours yet) and gave it an 'refresh'-flag to go with the optional cache mechanism:
var $=function(/*cache_enabled*/c){ // getElementById with optional caching & refresh
return c ?( c={}, function(s,r){return (!r && c[s]) || (c[s]=document.getElementById(s));}
):( function(s){return document.getElementById(s);} );
}(true); // or nothing or 0 etc to disable the cache
Note: dynamically created functions are slow (for some reason) so it has 2 functions so the browser can run them optimized (and the other should be cleared by the garbage collector).
To request a fresh just add a flag that evaluates to true as second argument, like: $('elm_id', 1)
Then I modified your addMainMenuListeners function a little to first test for the existence of a fresh getElementById and then add the eventListener via the freshly updated cached reference (so, essentially I changed nothing in the flow of your routine).
formatted to emphasize what changed and how it works
function addMainMenuListeners(){
$( 'start' , 1) && $( 'start' ).addEventListener('click', startGame);
$('instructions', 1) && $('instructions').addEventListener('click', instructions);
$( 'settings' , 1) && $( 'settings' ).addEventListener('click', settings);
$( 'back' , 1) && $( 'back' ).addEventListener('click', resetMainMenu);
$( 'volume' , 1) && $( 'volume' ).addEventListener('change', function(){
saveAndChangeVolume($('volume').value);
});
}
Finally, putting above 2 functions and the rest of your functions/html into this fiddle rendered a working result: http://jsfiddle.net/xHUGu/ !
Note: I had to substitute a dummy function startGame otherwise there would be a fatal error. The missing volume-functions were not critical.
I would like to point out that this is not really the way to go with your interface, there would be a lot of work you could save both yourself and the browser. You might want to look into div's (containing your subsections of html) and toggle them so there is only one visible. Like tabs. (Hint for google-query).
Credit still goes to Sukima ('the force is strong in this one'), but I felt it was a good idea to share the correct explanation to your problem (with proof) and not to waste the work that was done anyway (out of curiosity).
Hope this helps!
Disabling caching on the $ function worked. It was referencing to a destroyed HTML element, and that's why it didn't work. Also, setTimeouts helped for reliability in the case that innerHTML didn't execute in time.
I have made a list(<p>) with buttons. When I move my mouse over them it's a 1,2 sec delay before my textbox are marked with yellow to show where I can write. When I move my mouse away they turn normal(white).
My problem is when I quickly hover my mouse over the buttons back and forth a lot of the textboxes gets marked.
I had hoped the 1,2 sec delay would have worked then but it doesn't. But it works if I move my mouse slowly in and out of the button.
Here is a fiddle to it: http://jsfiddle.net/Pota/Fj6E6/
Here is my JavaScript code
$(function () {
$("p.pRespRoleId").mouseenter(function () {
var timeOut = 1200;
$this = $(this);
$this.data("delay", setTimeout(function () {
mouseInRespRoleId();
}, timeOut)
);
})
.mouseleave(function () {
$this = $(this);
if ($this.next(mouseOutRespRoleId()).is(":visible")) {
clearTimeout($this.data("delay"));
mouseOutRespRoleId();
}
else {
$this.next("p.pRespRoleId").show();
}
});
});
and
function mouseInRespRole()
{
var txtInRespRole = document.getElementById("<%=txtRespRoleName.ClientID %>");
txtInRespRole.style.background = "#FFFF00";
if (document.getElementById('txtRespRoleName').value == '')
{
document.getElementById('txtRespRoleName').innerHTML = txtInRespRole;
return false;
}
}
function mouseOutRespRole()
{
var txtOutRespRole = document.getElementById("<%=txtRespRoleName.ClientID %>");
txtOutRespRole.style.background = "white";
if (document.getElementById('txtRespRoleName').value == '')
{
document.getElementById('txtRespRoleName').innerHTML = txtOutRespRole;
return true;
}
}
Your jsFiddle is surely confusing to me (I am not sure what you are trying to achieve - there is a tangible possibility that you are overcomplicating things). I hope I got your requirement right...
Anyway, I believe your logic was right, but there were some flaws in the implementation. So, here is a modified (and partially corrected) version of your jsFiddle, which does what (I believe) you were trying to achieve.
Your use of '$this.next(mouseOutRespRoleId()).is(":visible")' was sure the most confusing, so I removed it completely. (In case it was fulfilling some other, not obvious purpose, you'll have to provide a more detailed description.)
The main problem was that $this.next(mouseOutRespRoleId()).is(":visible") was never evaluating to true, thus never clearing the timer that called mouseInRespRoleId().
EDIT:
I updated my jsFiddle illustration so that it takes care of IE9's strange behaviour (a.k.a. bug (?)). It should work without flickering now.
Short explanation of the problem:
Aparantly, in IE9 the mouse-events generation has some "timing issues", so that when entering (mouseOver) and leaving (mouseOut) a component multiple times rapidly, sometimes the mouse-events order gets messed up. E.g.:
The following event sequence (i.e. actual events):
mouseOver -> mouseOut -> mouseOver
May produce the following (obviously wrong) javascript-event sequence (i.e. events triggered by JS-engine in IE9):
mouseOver -> mouseOver(!) -> mouseOut(!)
So, I added an extra clearTimeout($this.data("delay")) in the "mouseentered" handler-function, in order to clear any pending scheduled executions of "mouseInRespRoleId".
It does not work perfectly on IE9 (and probably previous versions of IE - not tested), but it is as good as it can get (afaik).
(NOTE: It still works as intended on other (non-buggy) browsers.)
I have the following code:
function handle_paste_keydown(key)
{
if(key.keyCode == 86 && key.ctrlKey) // Ctrl + V
{
alert("Test...");
}
}
This works in IE, but none of the other browsers. My reason for doing this is that I have finished creating a rich-text editor, but I need to handle the onpaste event carefully because formatted text is able to make it in to my editor, which could pose a minor risk to security, but also butchers my layout if malicious <span>s and <div>s make it in.
My current method is to give focus to an off-screen textarea, which means all code will be pasted in to that (which removes formatting); then I immediately grab the textarea.value and insert it at the current caret position in my contentEditable <div>.
So anyway, how do I get the Ctrl+V to work in all browsers and why doesn't it work in its current state?
Thank you.
If it works in IE but nowhere else you did something wrong.
Use the keypress event rather than keydown.
http://jsfiddle.net/Lxvgr/1/
document.getElementById('foo').onkeypress = function(e) {
if(e.charCode == 118 && e.ctrlKey) alert('pasted');
};
#Eric Sites: "use jQuery" isn't the answer to every javascript question. including an entire external framework to solve a simple 4byte issue like this is ridiculous.