Use anchor tag to link to same page using react router hashlocation - reactjs-flux

Trying to link to the same page with anchor tag but as i am using react router HashLocation as below, router catches it preventing the anchor to work as normal in addition of producing error of "No route matches path".
Router.run(routes, Router.HashLocation, (Root) => { React.render(<Root/>, document.body); });
Same Problem has been asked in the link below with some hint of using "HistoryLocation" but i want to stick with "HashLocation" and those link do not provide concrete answer, thus need help:
1) How to use normal anchor links with react-router
2) Using React-Router to link within a page
I wonder if there are some kind of filter in router to exclude some hash so that i can use default same page anchor linking.

The whole point of using the HashLocation router is to use the # to handle routing, it's a bit of a hack to allow client side navigation, but in fact it's a Single Page Application.
You can't have more than one # in your url, it makes no sense for browsers to have multiple ones. With that in mind, I think you should handle the "in page" navigation (but in fact your whole site is the "in page navigation") yourself, maybe simply using some jQuery (or pure javascript) code to scroll to the specified DOM id maybe on some hook after react-router transition.

Try something like this.
componentDidUpdate() { if ((this.props.index == this.props.selected)) React.findDOMNode(this).scrollIntoView(); }

Related

ASP.NET Core MVC : Razor pages routing, incorrectly re-using previous route data

I'm working on a dotnet 6 mvc application using RazorPages, and I'm having a problem with strange routing behavior.
I have a RazorPage /Pages/News.cshtml
This page is accessible using the default route /news
When called without any parameters this page will display an index of news articles.
I also want this page to be able to display a specific news article, via a path like this...
/news/1234-my-news-article
To achieve this, I've added a config like so...
builder.Services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute("/News", "News/{id:regex(^\\d+\\-.*)?}");
});
In my templates, I can then use links like this...
<a asp-page="/News" asp-all-route-data="#(new Dictionary<string, string> { { "id", "1234-my-news-article" } })">My News Article</a>
or
<a asp-page="/News">All Articles</a>
However, once I've navigated to a specific article, the index link doesn't render correctly, and will instead link again to the same article. It appears to be re-using the current routing parameters.
Is there some way to avoid this?
update:
I've found a work-around, if I use this tag instead...
<a asp-page="/News" asp-route-id="">All Articles</a>
then it will link correctly to "/news".
It seems a bit counter-intuitive to have to explicitly set this to blank. I would have assumed it would default to unset, unless explicitly set otherwise.
This is known as ambient route values (https://www.learnrazorpages.com/razor-pages/tag-helpers/anchor-tag-helper#ambient-route-values), where the current route values are automatically added to outbound links which are generated by the anchor tag helper if the destination page is the same as the current page. In older versions of Razor Pages, this was the default behaviour for all pages.
As you have discovered, you can override this by setting the route value to an empty string, or as suggested elsewhere, to use a plain anchor tag for your link.
asp-page tag helper will add id value to the route by default.It is by design.If you don't want to add it,you can try to use href to replace asp-page:
All Articles

Single page application with Rails 4 and AngularJS

Ok, this idea might seem quite a bit crazy and it kindo' is (at least for me at my level).
I have a fairly standarad rails app (some content pages, a blog, a news block, some authentication). And I want to make it into a single page app.
What I want to accomplish is:
All the pages are fetched through AJAX like when using turbolinks, except that the AJAX returns only the view part (the yield part in the layout) withought the layout itself, which stays the same (less data in the responces, quicker render and load time).
The pages are mostly just static html with AngularJS markup so not much to process.
All the actual data is loaded separately through JSON and populated in the view.
Also the url and the page title get changed accordingly.
I've been thinking about this concept for quite a while and I just can't seem to come up with a solution. At this point I've got to some ideas on how this actualy might be done along with some problems I can't pass. Any ideas or solutions are greatly appreciated. Or might be I've just gone crazy and 3 small requests to load a page are worse then I big that needs all the rendering done on server side.
So, here's my idea and known problems.
When user first visits the app, the view template with angular markup is rendered regularly and the second request comes from the Angular Resource.
Then on ngClick on any link that adress is sent to ngInclude of the content wrapper.
How do I bind that onClick on any link and how can I exclude certain links from that bind (e.g. links to external authentication services)?
How do I tell the server not to render the layout if the request is comming from Angular? I though about adding a parameter to the request, but there might be a better idea.
When ngInclude gets the requested template, it fires the ngInit functions of the controllers (usually a single one) in that template and gets the data from the server as JSON (along with the proper page title).
Angular populates the template with the received data, sets the browser url to the url of the link and sets the page title to what it just got.
How do I change the page title and the page url? The title can be changed using jQuery, but is there a way through Angular itself?
Again, I keep thinking about some kind of animation to make this change more fancy.
Profit!
So. What do you guys think?
OK, in case enyone ever finds this idea worth thinking about.
The key can be solved as follows.
Server-side decision of whether to render the view or not.
Use a param in the ngInclude and set the layout: false in the controller if that param is present.
Have not found an easier way.
Client-side binding all links except those that have a particular class no-ajax
Here's a directive that does it.
App.directive('allClicks', function($parse) {
return {
restrict: 'A',
transclude: true,
replace: true,
link: function(scope, element, attrs) {
var $a = element.find('a').not($('a.no-ajax')),
fn = $parse(attrs['allLinks']);
$a.on('click', function(event) {
event.preventDefault();
scope.$apply(function() {
var $this = angular.element(event.target);
fn(scope, {
$event: event,
$href: $this.attr('href'),
$link: $this
});
});
});
}
};
})
And then use it on some wrapper div or body tag like <body ng-controller="WrapperCtrl" all-links="ajaxLink($href)"> and then in your content div do <div id="content" ng-include="current_page_template">
In your angular controller set the current_page template to the document.URL and implement that ajaxLink function.
$scope.ajaxLink = function(path) {
$scope.current_page_template = path+"?nolayout=true";
}
And then when you get your JSON with your data from the server don't forget to use history.pushState to set the url line and document.title = to setr the title.

MVC 3 Appending Anchor to outgoing URL

I am implementing a non-Javascript page for a client. The page contains a number of third party grids. When JS is turned off and a sort is performed the page i,s posted back to the server , which is fine. However, I want the page to navigate to the grid that was sorted.
I can do this by using anchors, and I have tested it. However, as I am new to MVC I don't know how to append the anchor to the outgoing URL.
For example I may get a URL like Team/User/42?SortGrid1-field-asc
After it has been processed by the controller I need the URL to be sent to the client as
Team/User/42?SortGrid1-field-asc#Grid1
Any ideas?
I have tried to append the anchor internally using lines like
return Redirect(Url.Action("User", "Team", new { Id = Id }) + "#Grid1");
But fail to see how to stop it going off in an infinite loop. If I redirect to another action then I go down a whole new path , which, code wise, will go on forever.
Have a look at the answer to a question I posted: How can I add an anchor tag to my URL?
I think you may have to go through the controller and use generateURL to get the anchor into the url

Is there a way to AJAX load a page and change URL in URL bar without hashing?

This is probably going to get a resounding no, but I am wondering if it possible to have the URl change dynamically with using hashing, and without invoking a http request from the browser?
My client is keen on using AJAX for main navigation. This is fine, when the end user goes to the front page first, but when they want to use the deep linking, despite it working, it forces an extra load time as the page loads the front page, then invokes the AJAX from the hash.
UPDATE: Could it be possible, given that what I want to avoid is the page reload (the reason is that it looks bad) to stem the reload by catching the hash with PHP before the headers are sent, and redirecting before the page load. This way only one page loads, and the redirect is all but invisible to the user. Not sure how to do this, but seems like it is possible?
Yes, this is possible. I often do this to store state in the hash part of the URL. The result is that the page doesn't reload, but if the user does reload, they're taken to the right page.
Using this method, the URL will look like: "/index#page=home" or "/index#page=about"
You'll need to write a JavaScript function that handles navigation, and you'll need a containing div that gets rewritten with the contents fetched from AJAX.
Home
About
Questions
<div id="content"></div>
<script type="text/javascript">
function link(page) {
location.hash = "page="+page;
loadPage(page);
}
// NOTE: This is using MooTools. Use the AJAX method in whatever
// JavaScript framework you're using.
function loadPage(page) {
new Request.HTML({
url: "/ajax/"+page+".html",
onSuccess: function(tree, elements, html) {
document.id('content').setProperty('html', html);
}
}).get();
}
</script>
Now, you'll also need to have something that checks the hash on page load to load the right content initially. Again, this is using MooTools, but use whatever onLoad method your JavaScript framework provides.
<script type="text/javascript">
document.addEvent('domready', function() {
parts = location.hash.split('=');
loadPage(parts[1]);
}
</script>
Ok, the problem is that opening an AJAX link of the form http://example.com/#xyz results in a full page being downloaded to the browser, and then the AJAX-altered content is changed once the page has loaded and checked the hash part of its URL. The user has a diconcerting experience.
You can hugely improve this by making a page that just contains the static elements - menus, etc. - and a loading GIF in the content area. This page checks its URL upon loading and dynamically fetches the content specified by the hash part. The page can have any URL you want; we'll use http://example.com/a. Links to this page (http://example.com/a#xyz) now provide a good user experience for users with scripting enabled.
However, new users won't come to the site by fetching http://example.com/a; they'll fetch http://example.com. This is fine - serve the full page, including the home page content and links that don't require scripting to work (e.g., http://example.com/xyz). A script run on loading this page should alter the href of AJAXable links to their AJAX form (http://example.com/a#xyz); thus the first link a user clicks on will result in a full page load but subsequent ones won't.
The only remaining problem is is a no-script user gets sent an AJAX link. You can add a noscript block to the AJAX page that contains a message explaining the problem and provides a link back to the homepage; you could include instructions on how to enable scripting or even how to modify the link by removing a# and pressing enter.
It's not a great answer, but you can offer a different link in the page itself; e.g., if the address bar shows /#xyz you include a link to /xyz somewhere in the page. You could also add a link or button that uses script to bookmark the page, which would again use the non-AJAX form of the link.

sIFR - override link click with onRelease?

I've got sIFR setup to replace a navigation menu (looks pretty slick). It's individually replacing the LIs and their internal links. I have an onRelease tag that throws properly, extracts the actual href link address, all good so far. I want to tie this into an AJAX page loader, with backwards-compatability (+SEO) for the individual pages being able to load themselves. I've tried return false like I would for standard links, no dice.
I'm assuming it doesn't work because it's onRelease, not onClick or something BEFORE it is already changing the page? onClick doesn't seem to be a valid sIFR function, documentation at http://wiki.novemberborn.net/sifr3/JavaScript+Methods says onRollOver, onRollOut, and onRelease. It would be a shame to have to pitch my entire AJAX system, there is hopefully a good workaround!
There isn't really an option to prevent the default behaviour. You can change it in sIFR.as though. Assuming the <li> contains just a <a> remove the following around line 505:
getURL(sIFR.instance.primaryLink, sIFR.instance.primaryLinkTarget);
That will prevent sIFR from following the URL when you click on the link. It'll still work with right-click though, but you might be able to fix that by changing (line 508):
menu.customItems = menuItems;
to
menu.customItems = [];

Resources