Using React-Router with browserHistory, how can I create a same-page link to an item on the page?
In one component:
<Link to='/coolRoute#coolThing'>Cool Thing</Link>
In another:
render () {
return (
<div id='coolThing'></div>
);
}
When I click the link the browser URL changes properly, but nothing actually happens (I would expect a scroll up/down the page to the element.
I know that the id is present on the page because doing document.getElementById('coolThing') works just fine.
Related
I have an anchor tag on a page in my Svelte app. The link to the anchor works on the page itself, but I can't link to the anchor from another page. And when I enter the URL with the anchor, the page doesn't scroll down. I need to be able to give people a link and have them go to a specific part of the page.
Here's the relevant code:
<script>
function scrollIntoView({ target }) {
const el = document.querySelector(target.getAttribute("href"));
if (!el) return;
el.scrollIntoView({
behavior: "smooth",
});
}
</script>
<nav>
<a href="#here" on:click|preventDefault={scrollIntoView}>go to anchor</a>
</nav>
<main>
<section id="section-1">
... lots of lorem ipsum ...
</section>
<section>
<h2 id="here">anchor</h2>
And I have a REPL here: https://svelte.dev/repl/e651218bdb47455d9cafe8bff27c8d7b?version=3.24.0
I'm using page.js for my routing to components -- I haven't found anything specific about targeting anchor tags in the documentation.
Any help would be greatly appreciated.
You don't need JS for smooth scrolling, just add some CSS:
/* :global if in component */
:global(html) {
scroll-behavior: smooth;
}
REPL
As for scroll on page load, that is an issue of client-side rendering. For SSR the CSS alone takes care of everything but if the element that should be scrolled to is added after the page is loaded, the scroll will not happen.
One way of dealing with that would be to add an onMount, ideally high up in the component hierarchy so it triggers after everything is mounted, which manually performs the scroll:
onMount(() => {
const { hash } = document.location;
const scrollTo = hash && document.getElementById(hash.slice(1));
if (scrollTo)
scrollTo.scrollIntoView();
});
(Some of that logic is from SvelteKit which does all that automatically.)
This is so simple I don't get how it could possibly go wrong. I'm trying to get a simple intra-page link to behave.
(If it's relevant, this is an angular 2 app, using routing.)
Here is a typical page:
Skip to main content
<div class="page-body">
<main>
<div class="content-body" id="content-start">
<h1>Employee Search</h1>
</div>
<main>
</div>
The URL of this page (in my dev env) is
http://localhost:49974/app/employee/search
When I click (or focus then press enter) on Skip to main content it should go to
http://localhost:49974/app/employee/search#content-start
but instead goes to
http://localhost:49974/app#content-start
(and then immediately switches to
http://localhost:49974/app/#content-start
)
I can't have messed up the linking itself; this must have something to do with how the routing is working.
It looks like I have to do it this way:
<a href="app/request/timeoff#content-start">
But that doesn't seem correct.
I don't know if this is a the correct way, or the angular way, but it works:
app.component.html:
Skip to main content
app.component.ts
export class AppComponent {
pageURL: string;
ngDoCheck() {
this.pageURL = window.location.href;
var link = this.pageURL.indexOf('#content-start');
if (link > -1) {
console.log(this.pageURL.substring(0, link));
this.pageURL = this.pageURL.substring(0, link);
}
}
}
every-page.html:
<h1 class="content-body" id="content-start">Page</h1>
Not sure if ngDoCheck is the appropriate event use.
Full disclosure: app.component is a wrapper - with header and the 'skip to content' link that contains all the pages and their content.
So, the logic for the 'skip to content' link exists once, while the actual content target #content-start lives in the top of each content page.
I have a menu header and when you click one of the menu links it directs to another page half way down (which i want) as it finds the relevant div id name. I was wondering if there is a way to clean the url back up again so it doesn't include the #id in my url? Tried window.location hash and this breaks it from scrolling and leaves the # in the url. Here is what i have:
In my menu: <li><a href="about#scroll-to" ....
And on the about page, it scrolls down to a div called #scroll-to..<div id="scroll-to"></div>
Any suggestions would be great. Thanks!
Using jquery, you can make a POST call to the target page when menu is clicked.
The POST data will contain the id of the div where you want to slide to.
On your target page, use your server language (php, asp) to output that id in a js variable and on document ready slide using jquery to that id.
Then you will have a clean url, and the page scrolling to your div.
---- edit: here comes the code!
Lets use jquery to make a POST to the target page, when a menu item is clicked. We will add a class, lets say, "mymenuitem". We will add this class to our link in the menu. So we will have
<li>Information about us</li>
(the onClick stops link from redirecting manually)
and an empty form (put it after the < body >)
<form id="slidinganchorform" method="post" action="YOURTARGETPAGE.HTML"></form>
then we will create the neccessary jquery so when the < a > tag with class "mymenuitem" is clicked, we will make a POST to the target page.
<script type="text/javascript">
jQuery(document).ready(function(){
$(".mymenuitem").click(function() {
// we will split the clicked href's value by # so we will get [0]="about" [1]="scroll-to"
var the_anchor_id_to_scroll_to = $(this).attr("href").split('#')[1];
// lets do the POST (we WILL TRIGGER a normal FORM POST while appending the correct id)
$("#slidinganchorform").append('<input type="hidden" name="anchorid" value="'+ the_anchor_id_to_scroll_to + '">');
$("#slidinganchorform").submit();
});
});
</script>
then in our YOURTARGETPAGE.HTML we will have something like (let's assume we use php)
<head>
<!-- make sure your jquery is loaded ;) -->
<?php
if($_POST['anchorid']!='')
{
?>
<script type="text/javascript">
jQuery(document).ready(function(){
// lets get the position of the anchor (must be like <a name="scroll-to" id="scroll-to">Information</a>)
var thePositiontoScrollTo = jQuery('#<?php echo $_POST['anchorid']; ?>').offset().top;
// Lets scroll
jQuery('html, body').animate({scrollTop:thePositiontoScrollTo}, 'slow');
});
</script>
<?php
}
?>
</head>
be sure the correct id must exist ;)
<a name="scroll-to" id="scroll-to">Information about us or whatever...</a>
(remove your old code because i changed some variable names and it will be difficult to debug if there are parts from the previous version. write everything from the start )
You can do this when the new page loads
history.pushState("", document.title, window.location.pathname);
However it will also remove the query string. Although, you could play with it a little bit to keep it
I'm replacing the standard "Reset your password" text link with a help' icon, but I discovered that when a jQuery Tooltip is on a link within an iframe, it remains open once the link is clicked until the parent page is refreshed.
I'm using inline frames, but I also experienced the same problem when linking to another page. I tried moving the title inside a <span> tag, as well as closing the iframe and opening a new one with the functions below, but the tooltip just remains open on the page.
UPDATE - I created a fiddle to demonstrate the problem http://jsfiddle.net/chayacooper/7k77j/2/ (Click on 'Reset Link'). I experience the problem in both Firefox & IE (it's fine in Chrome & Safari).
HTML
<img src="help.jpg">
Functions to close iframe and open new iframe
function close_iframe() {
parent.jQuery.fancybox.close();
}
function open_iframe() {
$.fancybox.open([{href:'reset_password.html'}], { type:'iframe'
});
}
I am using jquery-1.8.2, jquery-ui-1.9.1 and fancyapps2
Could be an incompatibility or bug between the fancybox and the jQueryUI tooltip.
Essentially, the fancybox is showing the second form but the browser is not seeing the mouseout event. You can check this by adding a callback function to the .close() event of the jQueryUI tooltip.
$('a[href="#inline_form1"]').tooltip({
close: function( event, ui ) {
console.log('closing')
}
})
You should be able to see closing in the console in IE, Firefox and Chrome when the mouse moves out of the "Reset Link" anchor. However, when clicking "Reset Link" in Chrome you see the closing log line again but in IE9 it does not appear again. So the browser is missing the event.
We can work around this by manually calling .tooltip('close') when "Reset Link" is clicked, like this:
$('a[href="#inline_form1"]').on('click', function() {
$(this).tooltip('close')
})
There is a small problem with the way in which the tooltips are created which means that with just the above click handler it will error with
Uncaught Error: cannot call methods on tooltip prior to initialization; attempted to call method 'close'
This seems to be caused by using the $(document).tooltip() method which uses event delegation for all elements with a title attribute. This is the simplest way of creating tooltips for all elements so I understand why this is used but it can add unnecessary events and handling to the whole page rather than targeting specific elements. So looking at the error it is telling us that we need to explicitly create a tooltip on the element we want to call 'close' on. So need to add the following initialisation
$('a[href="#inline_form1"]').tooltip();
Sp here is the completed JavaScript
$(function () {
$(".fancybox").fancybox({
title: ''
})
$(".fancybox").eq(0).trigger('click')
$(document).tooltip();
$('a[href="#inline_form1"]').tooltip()
$('a[href="#inline_form1"]').on('click', function() {
$(this).tooltip('close')
})
})
Note: You only need one jQuery document.ready wrapping function - the $(function (){ ... }) part :-)
In my jquery-mobile (1.0RC2) application, I have two pages: test1.html, test2.html
The first page, test1.html, includes an collabsible-set, where I expand one collabsible item via script in the pageinit event listener (tried both pageshow and pageinit):
$('#page1').live( 'pageinit', initPage);
function initPage() {
alert('initPage!'); // this line seems to be always getting executed
$('#my_expandable').trigger('expand'); // ... but this line doesn't when coming back via a back link!
}
This works fine on the first call of the page.
Then I have a link that leads me to the second page test2.html, as follows:
<script>
function goPage2(criteria) {
$('#page1').die( 'pageinit', initPage);
$.mobile.changePage( "test2.html", {reverse: false, reloadPage: true} );
}
</script>
page 2
When I then go back to the first page via
<script>
function goPage1() {
$.mobile.changePage( "test1.html", { reverse: true, reloadPage: true} );
}
</script>
test
only the alert message in the pageinit event listener of test1.html is executed, but the collapsible is not being expanded through the
You can see the sample in action here: http://bit.ly/rr0dq3
How to reproduce the problem:
load test1.html at http://bit.ly/rr0dq3
you will get an alert message, and the collapsible will be expanded
click on the button 'GoTo page2' and you will come to the second page test2.html
on this second page, click on the gray button 'test', and you will come back to the first page test1.html
the problem now: as you can see, the alert command of the pageinit event of test1.html is being executed, but expanding the collapsible isn't - why not? Obviously the pageinit event listener method is being entered properly, but only the collapsible seems to have a problem here.
I think it might be a bug (filed a report here https://github.com/jquery/jquery-mobile/issues/2791), but maybe somebody else has an idea for that.
Workaround:
Both the alert and the collapsible expanding is being executed when I use a different way to to open the second page test2.html, using
window.location.href = "test2.html";
instead of
changePage(...);
But it's not very satisfying. Why does it not work properly if I use the the page injection way? I already call the die() method when I open the different pages in order not to have multiple pageinit event listeners keeping hanging around.
Have you tried using the data-attribute for collapsible content areas that makes them load expanded:
data-collapsed="false"
Here is a link to the docs for this behavior: http://jquerymobile.com/demos/1.0rc2/docs/content/content-collapsible.html