I have some functionality that i need to change whenever the path changes. Often you would solve that problem with the following.
myProp: ( ->
# .. Do something here
).property('currentPath')
The problem with currentPath, is that it only detect route changes, so the following transition is not detected.
/blog/my-awesome-blog-post -> /blog/new-awesome-post
Because they are working on the same route, but i need to detect when a transition like that happens, as i need to update my social media sharing links.
I have tried something like the following with no luck.
App = Ember.Application.create({
conf: config,
currentPathName: '',
});
App.initializer({
name: 'Path name observer',
initialize: function(container, application) {
var router = container.lookup('router:main');
router.addObserver('url', function() {
var lastUrl = undefined;
return function() {
Ember.run.next(function() {
var url = router.get('url');
if (url !== lastUrl) {
App.set('currentPathName', url);
lastUrl = url;
}
});
};
}());
}
});
And then observe 'App.currentPathName', but this somehow messes the router up, as the url's suddenly doesn't change on click.
Any suggestions?
This is the solution i got from a friendly soul # github. This is not currently documented, but works quiet nicely.
Ember.Router.reopen({
doSomethingOnUrlChange: function() {
console.log(this.get('url'));
}.on('didTransition')
});
Related
I am using sammy.js for single page application in asp.net mvc. Everything is fine, but I am facing one problem which is that I can not reload the page. For example When I am in the dashboard my URL is
http://localhost:1834/#/Home/Index?lblbreadcum=Dashboard
layout.cshtml
<script>
$(function () {
var routing = new Routing('#Url.Content("~/")', '#page', 'welcome');
routing.init();
});
</script>
routing.js
var Routing = function (appRoot, contentSelector, defaultRoute) {
function getUrlFromHash(hash) {
var url = hash.replace('#/', '');
if (url === appRoot)
url = defaultRoute;
return url;
}
return {
init: function () {
Sammy(contentSelector, function () {
this.get(/\#\/(.*)/, function (context) {
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run('#/');
}
};
}
I want to reload the page by clicking the dashboard menu/link. But click event not firing because link is not changing. But if I want to go another page then it is fine. Please help me out. Thanks.
I think you have to append the same partial again. You can't "update" the partial in that meaning.
As you say in your post, when you click another link and then back again it works.
That's what you'll have to do. Append the same page/partial again, by doing that you clear all variables and recreate them, by that simulating a refresh.
EDIT: Added example
Observe that I didn't copy your code straight off but I think you'll understand :)
And I don't use hash (#) in my example.
var app = Sammy(function () {
this.get('/', function (context) {
// context is equalient to data.app in the custom bind example
// currentComponent('home'); I use components in my code but you should be able to swith to your implementation
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
this.bind('mycustom-trigger', function (e, data) {
this.redirect('/'); // force redirect
});
this.get('/about', function (evt) {
// currentComponent('about'); I use components in my code but you should be able to swith to your implementation
var url = getUrlFromHash(context.path);
context.load(url).swap();
});
}).run();
// I did an easy example trigger here but I think you will need a trigger on your link-element. Mayby with a conditional check wheter or not to trigger the manually binding or not
$('.navbar-collapse').click(function () {
app.trigger('mycustom-trigger', app);
});
Please read more about events and routing in sammy.js
Good luck :)
An easier and cleaner way to force the route to reload is to call the Sammy.Application refresh() method:
import { sammyApp } from '../mySammyApp';
const url = `${mySearchRoute}/${encodeURIComponent(this.state.searchText)}`;
if (window.location.hash === url) {
sammyApp.refresh();
else {
window.location.hash = url;
}
I'm trying to get pushState to work in my backbone app. It works fine when just clicking the link. But if i refresh a page i get 404.
Router
Router = Backbone.Router.extend({
routes: {
'home': 'home'
},
home: function() {
new HomeView({el:'#main-view'})
}
});
When a-tag gets clicked:
event.preventDefault();
App.navigate(event.target.pathname, { trigger: true });
start history:
Backbone.history.start({pushState:true});
and html:
<li>
home
</li>
Whats wrong here?
The problem is you use a real HTML link, so it refreshes the page, it's the normal behaviour.
But you would like to change only the current route, not to reload the page.
For that, you can handle the links to say to Backbone : "handle my links !".
Here is an example of the JS that I use to handle links that have "innerlink" CSS class as a route.
'use strict';
var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;
module.exports = function() {
// Use absolute URLs to navigate to anything not in your Router.
var openLinkInTab = false;
// Only need this for pushState enabled browsers
if (Backbone.history._hasPushState) {
// console.log('YES you have push state !');
$(document).keydown(function(event) {
if (event.ctrlKey || event.keyCode === 91) {
openLinkInTab = true;
}
});
$(document).keyup(function() {
openLinkInTab = false;
});
// Use delegation to avoid initial DOM selection and allow all matching elements to bubble
$(document).on('click', 'a.innerlink', function(evt) {
// Get the anchor href and protcol
var href = $(this).attr('href');
var protocol = this.protocol + '//';
console.log('backbone_pushstate_router:', href, protocol);
evt.preventDefault();
// Ensure the protocol is not part of URL, meaning its relative.
// Stop the event bubbling to ensure the link will not cause a page refresh.
if (!openLinkInTab && href.slice(protocol.length) !== protocol) {
evt.preventDefault();
// Note by using Backbone.history.navigate, router events will not be
// triggered. If this is a problem, change this to navigate on your
// router.
Backbone.history.navigate(href, true);
}
});
} else {
console.warn('no push state');
}
};
Enjoy :)
I'm trying to create a basic webapp that displays images when a specific URL is reached. In this case, I'm using backbone.js's hash system.
I'm trying to make it so that when "www.website.com/index.html#1" is reached, the first image is displayed using some JavaScript that I have. I also need it so that if "www.website.com/index.html#1/#3/#5" is reached, the first, third, and fifth image is displayed. I know that I have to use multiple routes to do this, but I'm not sure how.
I have one working route for the first image that works awesomely. I just don't know how to adapt it so that it works with multiple routes.
Here's the working hash -
<script>
$(function(){
var hideOne = function () {
//alert("hideOne");
var elem = document.getElementById("one");
elem.className = "hide";
};
var Workspace = Backbone.Router.extend({
routes: {
"test":"test",// #test
},
test: hideOne
});
var router = new Workspace();
Backbone.history.start();
});
</script>
It's awesome, it works, it doesn't even refresh the page. But when I try to add another route to that, it all fails. Like, if I added a "test1":"test1" under the "test":"test", the original "test":"test" won't work anymore(neither will the new one, of course).
I've even tried copying+pasting that entire block of code and trying to make a whole new route block of code. That doesn't work either. I'm really stumped here.
Any suggestions would be awesome.
Thanks
You should limit the scope of your first use case. Don't depend on external functions for now. Do something like
routes: {
"test":function(){
alert("test");
},
"test2":function(){
alert("test2");
}
},
Then change to
routes: {
"test":"test",
"test2":"test2"
},
{
test: function(){
alert("test");
},
test2: function(){
alert("test2");
}
}
Read more: http://mrbool.com/backbone-js-router/28001#ixzz3ANyS0hkR
Once you have that working, then start working on DOM manipulation.
routes: {
"?*:queryString": 'showImages'
},
showImages: function(queryString) {
console.log(queryString); // #1#3#5
}
You can use the route "?*:queryString" to match this URL "www.website.com/index.html#?#1#3#5".
The functions "showImages" will be called and passing the value #1#3#5 in the queryString param.
So from other questions posted on StackOverflow, and some that I posted myself, some great users have helped me out and I've solved it.
Here's the code that I have to use -
<script>
$(function(){
var hideMany = function () {
var toHide = [].slice.call(arguments);
toHide.forEach(function (id) {
if(id === null) { return }
var elem = document.getElementById(id);
if(elem) {
elem.className = "hide";
}
});
};
var Workspace = Backbone.Router.extend({
routes: {
"hide(/:a)(/:b)(/:c)" : "test"
},
test: hideMany
});
var router = new Workspace();
Backbone.history.start();
});
</script>
So when you type "www.website.com/index.html#hide/ID1/ID2/ID3", it'll hide the elements with the IDs that you typed in.
I don't fully understand it, but I'm working on breaking it down and figuring out how it works. Thanks for all the help, guys!
I have made a solution for my website which includes using ajax to present the general information on the website. In doing this, I am changing the URL every time a user loads some specific content with the window.history.pushState method. However, when I press backspace or press back, the content of the old url is not loaded (however the URL is loaded).
I have tried several solutions presented on SO without any luck.
Here is an example of one of the ajax functions:
$(document).ready(function(){
$(document).on("click",".priceDeckLink",function(){
$("#hideGraphStuff").hide();
$("#giantWrapper").show();
$("#loadDeck").fadeIn("fast");
var name = $(this).text();
$.post("pages/getPriceDeckData.php",{data : name},function(data){
var $response=$(data);
var name = $response.filter('#titleDeck').text();
var data = data.split("%%%%%%%");
$("#deckInfo").html(data[0]);
$("#textContainer").html(data[1]);
$("#realTitleDeck").html(name);
$("#loadDeck").hide();
$("#hideGraphStuff").fadeIn("fast");
loadGraph();
window.history.pushState("Price Deck", "Price Deck", "?p=priceDeck&dN="+ name);
});
});
Hope you guys can help :)
pushState alone will not make your page function with back/forward. What you'd need to do is listen to onpopstate and load the contents yourself similar to what would happen on click.
var load = function (name, skipPushState) {
$("#hideGraphStuff").hide();
// pre-load, etc ...
$.post("pages/getPriceDeckData.php",{data : name}, function(data){
// on-load, etc ...
// we don't want to push the state on popstate (e.g. 'Back'), so `skipPushState`
// can be passed to prevent it
if (!skipPushState) {
// build a state for this name
var state = {name: name, page: 'Price Deck'};
window.history.pushState(state, "Price Deck", "?p=priceDeck&dN="+ name);
}
});
}
$(document).on("click", ".priceDeckLink", function() {
var name = $(this).text();
load(name);
});
$(window).on("popstate", function () {
// if the state is the page you expect, pull the name and load it.
if (history.state && "Price Deck" === history.state.page) {
load(history.state.name, true);
}
});
Note that history.state is a somewhat less supported part of the history API. If you wanted to support all pushState browsers you'd have to have another way to pull the current state on popstate, probably by parsing the URL.
It would be trivial and probably a good idea here to cache the results of the priceCheck for the name as well and pull them from the cache on back/forward instead of making more php requests.
This works for me. Very simple.
$(window).bind("popstate", function() {
window.location = location.href
});
Have same issue and the solution not working for neither
const [loadBackBtn, setLoadBackBtn] = useState(false);
useEffect(() => {
if (loadBackBtn) {
setLoadBackBtn(false);
return;
} else {
const stateQuery = router.query;
const { asPath } = router;
window.history.pushState(stateQuery, "", asPath);
},[router.query?.page]
I'm trying to use Backbone.js to handle the browser history. I'm not setting up Views / Models because I don't want it to handle this, and probably because of this I'm not getting it to work properly.
At this point my page is changing urls. Like:
domain.com/services
domain.com/products
domain.com/contact
domain.com/gallery
domain.com/gallery/photo1
The problem is: if I try to reload the page at domain.com/gallery/photo1. I get the error Uncaught SyntaxError: Unexpected token <
All other pages with just one level permalink works properly on reload. Am I missing something on Backbone?
I'm just using Backbone.Router and Backbone.history.
Is there any simple tutorial on how to set up a site with backbone.js? Just the history thing?
Here's my script:
var Router;
var myRouter;
$(document).ready(function(){
Router = Backbone.Router.extend({
initialize : function(options) {
//
},
routes: {
'' : 'home',
'*actions' : 'pages'
},
home : function() {
this.render('/');
},
pages : function(actions) {
this.render(actions);
},
render : function(path) {
var fullLine = '';
path = (path === '/' || path === '')? '/' : path;
console.log('path: ' + path);
}
});
myRouter = new Router();
Backbone.emulateHTTP = true;
Backbone.emulateJSON = true;
Backbone.history.start({pushState: true, root: "/backbone_teste/"});
// MENU CLICK
$('.menu').children('li').each(function(){
$(this).click(function(){
myRouter.navigate($(this).attr('data-id'), true, true);
});
});
});
Thanks for your help!
Problem Solved:
I just added to my index.php file the following code at the head section:
<base href="http://localhost/backbone_teste/" />
And it works.
Anyway I would like to know why this happens and why Backbone.js documentation don't mention this.
I found the solution at this link: HTML5 History / pushState URLs, .htaccess and You
Thanks