I am writing a page, where you click a button, a new div gets created and appended to the end of the page. After the div is drawn I want the page to scroll to it, but it's not working.
All the drawing etc. all works fine.
Inside the console, when I manually execute the scrollIntoView
function on any of the elements, it works just fine, i.e., the screen does indeed scroll to that div just fine.
Somehow this clicking thing is ruining the scroll? Maybe the browser doesn't allow you to scroll to something else right after you release the click?
Here's the codesandbox: https://codesandbox.io/s/wild-framework-uiz9t0?file=/src/index.js:0-232
Here's the code copied over from codesandbox.
html
<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="app"></div>
scroll
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<div
style="height: 100px; width: 100px; background-color: yellow;"
id="yellow_box"
>
yellow box
</div>
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<script src="src/index.js"></script>
</body>
</html>
javascript
function scrollYellowBox() {
const box = document.getElementById("yellow_box");
box.scrollIntoView();
}
const btn = document.getElementById("btn-scroll");
btn.addEventListener("click", scrollYellowBox);
Found a tutorial here where it seems to work on a click: https://www.javascripttutorial.net/javascript-dom/javascript-scrollintoview/. But don't see how what they're doing is different from what I'm doing...
Update: so seems like there's a behavior where if you click on a link / button, the browser automatically scrolls to that thing you just clicked. Which I guess makes sense but in this case I need to override it somehow?
Thanks!
Your button is not really a button: <button /> but a link <a />. By default the link will always try to navigate to the location defined by the href attribute. In your case this causes the browser to scroll to the yellow box and then back to the root of the document.
You can fix the issue by either making the button a real button
like so:
<button id="btn-scroll" class="btn">scroll</button>
You can also prevent the default behavior of the link or any other clickable element; by calling preventDefault() on the passed event at the beginning of the event handler callback, like so:
function scrollToYellowBox (e) {
e.preventDefault()
const box = document.getElementById("yellow_box");
box.scrollIntoView();
}
Your btn is a link pointing to #, which default behavior is scrolling the page to top. Change the link to a real button, or prevent the link default behavior:
function scrollYellowBox(e) {
// stop the default behavior
e.preventDefault();
// your other logics
// ...
}
Related
This question already has answers here:
In JavaScript, how can I open a page in a new browser window and scroll to a specific position?
(6 answers)
Closed 3 years ago.
Let’s say there is this html file that just has a button.
In the JavaScript file (added into the html file), jQuery is used to give the button a click function and it executes:
window.open('some-url');
This code opens the url in a new page but I want to be able to do things with that page whether it be to close it or to scroll it to a position.
I was think about doing this:
var web = window.open('some-url');
web.scrollTo(0,400);
However, this piece of code does not scroll to y-position of 400 in the newly opened link. Is there a way where I can make the ‘window’ refer to not ‘this’ but the some-url window?
With Simple Anchor Tag
id="abc"
With Javascript
Current Window
This one is easy. a window will always refer to the current window.
New Popup Window
If you open a window using window. open, you’ll get a reference to the window you opened.
var newWin = window.open('https://www.google.com', 'windowName');
Existing Popup Window
If someone has opened a popup window with window.open, and you know the window name they used, you can get a handle on that window by calling window. open without an empty string as the URL, and with the same name.
var existingWin = window.open('', 'windowName');
This will even work if the popup window was opened from a different frame on the same domain.
In modern browsers, this will even work if the window was opened from a different frame on a different domain. But be warned — this can cause some strange behavior in IE.
Popup Windows as they open
If you’re writing a library and you need to keep a collection of popup windows that are opened by any other library or javascript code, you can monkey patch window.open:
var windows = [];
var winOpen = window.open;
window.open = function() {
var win = winOpen.apply(this, arguments);
windows.push(win);
return win;
};
The short answer is no.
The long answer is no because it would be a huge security vulnerability if you could execute scripts on another website. Most websites link important sections of content with jump links https://blog.hubspot.com/marketing/jump-link-same-page.
Basically the website has an anchor tag with and ID attribute, and that ID attribute can be referenced with in the URL like https://www.some-ur.com/test#jump-to-id
It does seems that window.open does support a third argument where you can specify a top value as well https://www.w3schools.com/jsref/met_win_open.asp
First and foremost, why do you want to do that?
Secondly, is there content on the page you are referencing at the 400 y position? I know this question sounds stupid, but I have to ask b/c It worked for me.
Copy/Paste This:
<!DOCTYPE html>
<html>
<body>
<p>Click the button to open a new window called "MsgWindow" with some text.</p>
<button onclick="myFunction()">Try it</button>
<script>
function myFunction() {
var myWindow = window.open("", "MsgWindow", "width=200,height=600");
myWindow.document.write("<p>This is 'MsgWindow'. I am 200px wide and 900px tall!</p><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />p");
myWindow.scrollTo(0,400);
}
</script>
</body>
</html>
To this: https://www.w3schools.com/jsref/met_win_open.asp
I've been trying for the last few days to Lazy load Livefyre or Disqus on scroll distance from top (as opposed to the usual triggers of loading once they reach to the comments section) so the comments are already loaded by the time the bottom of the post is reached.
I found this tutorial: http://christian.fei.ninja/how-to-lazy-load-disqus-comments/
But unfortunately I can't get it to work. After spending hours working my little knowledge of coding I've come to the discovery the reason nothing happens is because the disqus embed.js file throws an error itself. It attempts to use "appendChild" on an undefined variable in one of its functions. Their code is minified so I can't make any actual sense of the error.
My guess is that the tutorial is missing some HTML markup that is necessary for the discus embed code to work properly. So I've been trying to use Livefyre instead. This is what I have so far:
<head>
<script type="text/javascript" src="http://zor.livefyre.com/wjs/v3.0/javascripts/livefyre.js"></script>
<script type="text/javascript">
var comments = document.getElementsByClassName('comments')[0],
livefyreLoaded=false;
function loadLivefyre() {
var articleId = fyre.conv.load.makeArticleId(null);
fyre.conv.load({}, [{
el: 'livefyre-comments',
network: "livefyre.com",
siteId: "XXXX",
articleId: articleId,
signed: false,
collectionMeta: {
articleId: articleId,
url: fyre.conv.load.makeCollectionUrl(),
}
}], function() {});
livefyreLoaded = true;
}());
//Get the offset of an object
function findTop(obj) {
var curtop = 0;
if (obj.offsetParent) {
do {
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return curtop;
}
}
if(window.location.hash.indexOf('#comments') > 0)
loadLivefyre();
if(comments) {
var commentsOffset = findTop(comments);
window.onscroll = function() {
if(!disqusLoaded && window.pageYOffset > commentsOffset - 1500) {
console.log('load comments, NOW!!');
loadLivefyre();
}
}
}
</script>
</head>
<body>
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<div class="comments"></div>
</body>
But I know little about javascript and this is my poor patch job.
I have a page where users edit a grid of data that contains up to 400 form fields. Think inline editing of a table.
The problem is where most of the form fields are select dropdowns, some of which can contain up to 1,000 options.
This is causing browsers to use a lot of memory, and to run far too slowly.
Is there some way to improve performance here, perhaps by dynamically filling the dropdown every time it's clicked, and clearing all but the selected option when leaving the dropdown?
I personally wouldn't advise clearing all other options from a select dropdown when a user selects one, in case they select the wrong one.
If you still would like to do this, use something similar to the following, to achieve it:
HTML Example
<select id="long_select">
<option value="1">test1</option>
<option value="2" selected="selected">test2</option>
<option value="3">test3</option>
<option value="4">test4</option>
<option value="5">test5</option>
</select>
JavaScript Example
// ITERATE THROUGH ALL SLEECTS ON THE PAGE, ADDING A FUNCTION TO THEIR 'onchange' EVENT HANDLER, WHICH WILL EXECUTE WHEN THE USER CHANGES THE SELECTS OPTION
var selects = document.getElementsByTagName('select');
var len = selects.length;
while(len--)
{
selects[len].onchange = select_delete;
}
// THIS FUNCTION CAPTURES THE SELECTED OPTION, CLEARS ALL OPTIONS AND APPENDS THE SELECTED OPTION TO THE SELECT'S OPTIONS COLLECTION, LEAVING ONLY ONE OPTION
function select_delete()
{
var item = this[this.selectedIndex];
this.options.length = 0;
this.appendChild(item);
}
And here's a working JSFiddle: http://jsfiddle.net/93o0qphv/1/
EDIT:
To dynamically populate select elements, you can create new option element, set it's 'text' and 'value' properties, and add it to the desired select.
HTML
<select id="first_select"></select>
JAVASCRIPT
// POINTER TO DESIRED SELECT
var select = document.getElementById('first_select');
// ARRAY HOLDING ONE OBJECT PER OPTION
var options_array = [{"textvar":"Option 1","valuevar":1},{"textvar":"Second option","valuevar":2}];
// ITERATE THROUGH ARRAY, USING EACH OBJECTS 'textvar' AND 'valuevar' AS THE NEW OPTIONS 'text' AND 'value' PROPERITES, THEN ADD NEW OPTION TO THE SELECT
for(var c=0;c<options_array.length;c++)
{
var new_option = document.createElement('option');
new_option.text = options_array[c].textvar;
new_option.value = options_array[c].valuevar;
select.appendChild(new_option);
}
Here's an example: http://jsfiddle.net/ShadeSpeed/gxxugp6v/
I hope this helps!
Dan.
I've had to do something similar before.
One of your options is to AJAX load options for select boxes that are visible on the page at the current moment. So something like this: (Fiddle for if the code snippet doesn't work)
function checkScroll(el) {
var top_of_object = el.offset().top;
var top_of_window = $(window).scrollTop();
var bottom_of_object = el.offset().top + el.outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
if ((top_of_object > top_of_window && bottom_of_object < bottom_of_window) && el.is(':empty')) { // If the element is in view and it's empty
el.load('ajax/MyURL?Select=thisSelect'); //Run ajax call to populate the element
} else if (top_of_object < top_of_window || bottom_of_object > bottom_of_window) {
el.empty(); // Empty elements not in view
}
}
function fireScroll() {
$('select').each( function() { //Loop through all selects
checkScroll($(this));
});
}
var timer;
$(window).scroll(function(){
timer && clearTimeout(timer);
timer = setTimeout(fireScroll, 100); // Make it only fire when you stop scrolling
});
fireScroll();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select></select><select></select>
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<select></select><select></select>
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
<select></select><select></select>
You AJAX call would then just need to return a string that was something like <option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option><option>MyOption</option>
I have 5 text boxes pre-defined in a form.
Is it possible to use JQuery/JavaScript to:
1. Keep only one textbox visible when the page containing the form is loaded.
2. Can there be A more link/button to show the other 4 text boxes, one at a time.
3. Can we disable the link/button from adding another text box, because only 5 textboxes are predefined.
I am working with "securefiles" type in CouchCMS. And have to achieve this at the front end.
My current front definition of the text boxes are:
<cms:input type="bound" name="ibox1" /><br /><br />
<cms:input type="bound" name="ibox2" /><br /><br />
<cms:input type="bound" name="ibox3" /><br /><br />
<cms:input type="bound" name="ibox4" /><br /><br />
<cms:input type="bound" name="ibox5" />
And the bounded type is defined as:
for each textbox.
Of course it's possible. You can have a div container for all your predefined inputs, and when a new one is created, put it below the last one.
HTML:
<div id="where_boxes_go">
<input type="bound" name="ibox1">
<input type="bound" name="ibox2">
<input type="bound" name="ibox3">
<input type="bound" name="ibox4">
<input type="bound" name="ibox5">
</div>
<span class="more-inputs">Add</span>
CSS
.hidden {
display: { none; }
}
JQUERY
$(document).ready(function() {
$(".more-inputs").on("click", function() {
$(".form").each(function() {
if( $(this).hasClass("hidden") ) {
$(this).removeClass("hidden");
return false;
}
});
});
});
This will make that your text, or bounds, our whatever you want starts hidden except the first one. If you click the Add button, it will show the next one.
It won't matter if there is no more text boxes, the button won't do anything, you will have to check inside the each() function if a counter reached 5, and then add a class for changing it's CSS to one that make the user know that he can use the button.
Demo: http://jsfiddle.net/3sex8mqf/1/
You could do the following in jQuery.
Demo#fiddle
var $inputs = $("input[type='bound']"), count = 0;
$inputs.first().show();
$(".more").on("click", function(e) {
e.preventDefault();
count++;
$inputs.filter(":eq("+count+")").show();
if ($inputs.length === count + 1) {
$(this).hide();
}
});
HTML:
<input type="bound" name="ibox1" /><br /><br />
<input type="bound" name="ibox2" /><br /><br />
<input type="bound" name="ibox3" /><br /><br />
<input type="bound" name="ibox4" /><br /><br />
<input type="bound" name="ibox5" />
<button class="more" style="cursor: pointer">Show More</button>
CSS:
input[type="bound"] { display: none; }
/* OR
input { display: none; }
*/
I'm trying to solve this problem, although I'm not a js developer and my implementations are pretty lame sometimes.
I defined in external js this function:
function moveScroller() {
var move = function() {
var st = $(window).scrollTop();
var ot = $("#scroller-anchor").offset().top;
var s = $("#scroller");
if(st > ot) {
s.css({
position: "fixed",
top: "60px"
});
} else {
if(st <= ot) {
s.css({
position: "relative",
top: ""
});
}
}
};
$(window).scroll(move);
move();
}
and than in html in body i have this code:
<div style="width:900px; position:relative; margin:0 auto; border:1px solid red; padding-top:300px; padding-left:60px;">
<div id="scroller-anchor"></div>
<div class="info_holder" id="scroller">Information in here and here</div>
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
random and random<br /><br /><br /><br /><br />
</div>
<script>
$(document).ready(function() {
moveScroller();
});
</script>
I tried the body part of the script execute without $(document).ready but it gives me the same error Uncaught ReferenceError: moveScroller is not defined.
http://jsfiddle.net/A6gYg/76/
or http://atargeta.staging.wpengine.com/modules/ if you open console you should see the only error.
Change your javascript to be placed in the <head>. That way it is available once your $(document).ready(); call happens. The way you have it set up now, the function will be created after you use it. You want it to be created before you use it.
It is not a best practice to place javascript in the <head>, but for the sake of example, placing it in the <head> will fix your issue.