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;
}
Related
This may be a really simple problem but I can't seem to find why this is happening. I'm trying to develop a SPA in vanilla js using webpack, so far I was able to implement routing
with hashchange event and triggering rerendering. But when I tried to add an active class to the relevant link though when the hash changes, It doesn't work. But when I log to the console, it seems that class was added successfully, but in the HTML it doesn't get updated. Why is this?
this is my hashchange listener,
window.addEventListener("hashchange", (e) => {
const hash = window.location.hash.replace("#", "");
const view = routes.find((route) => {
return route.path == hash;
});
const links = document.querySelectorAll(".nav-list--link");
app.render(view.name);
links.forEach((l) => {
const hashHref = l.getAttribute("href").replace("/#", "");
if (hash === hashHref) {
l.classList.add("active");
console.log(l, l.classList);
} else {
l.classList.remove("active");
console.log(l, l.classList);
}
});
});
And this is the console output,
This is the HTML,
I don't understand why it doesn't update in the HTML if it's shown as updated in Javascript
there is a page with some basic HTML that I cannot touch that looks like this:
<a class="continue-shopping" href="https://someURL">Continue shopping</a>
what I want to do is send the user to a different link when they click on the someURL text link. the user can come to a page containing this html from many other pages.
i have tried many hours but cannot get my js to recognize a click event for a class associated with hyperlinked text. i could really use some help here. this is the js code i wrote which does not work
window.onload = function() {
prepEventHandler();
}
function prepEventHandler () {
var myClass = document.getElementsByClassName("continue-shopping");
myClass[0].onclick=window.open(document.referrer,"_self");
/* which make my pages go haywire OR THIS -- which also does not work */
myClass[0].addEventListener("click", function() {
window.open(document.referrer,"_self");
}
)
}
It just keeps ignoring the second function, and I am sure I am doing some really basic that is wrong. Again, thanks for any help!
Apart from preventDefault() you could also use return false
window.onload = function () {
var myClass = document.querySelector(".continue-shopping")
.onclick = function () {
window.location.href = "http://elsewere.com";
return false;
}
}
this code should work but it no longer does and i do not know why any hint much appreciated - there seems to be some problem with myClass[0]
window.onload = function() {
var myClass = document.getElementsByClassName('continue-shopping');
myClass[0].addEventListener("click", function(e) {
e.preventDefault();
window.location.href = document.referrer;
});
}
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]
My site is working much quicker thanks to some code I painstakingly modified, but I would love if the browsers' back/forwards buttons worked. Right now, with my code below, the browser address bar never changes. When someone clicks 'Back', it takes them out of the application.
Would there by any easy way of changing this so the browser's back/forward button worked? Or else if someone could point me in the right direction. Thanks for any help.
$(document).on("ready", function () {
//I want to load content into the '.page-content' class, with ajax
var ajax_loaded = (function (response) {
$(".page-content")
.html($(response).filter(".page-content"));
$(".page-content .ajax").on("click", ajax_load);
});
//the function below is called by links that are described
//with the class 'ajax', or are in the div 'menu'
var history = [];
var ajax_load = (function (e) {
e.preventDefault();
history.push(this);
var url = $(this).attr("href");
var method = $(this).attr("data-method");
$.ajax({
url: url,
type: method,
success: ajax_loaded
});
});
//monitor for clicks from menu div, or with
//the ajax class
//why the trigger?
$("#menu a").on("click", ajax_load);
$(".ajax").on("click", ajax_load);
$("#menu a.main").trigger("click");
});
Here is a way of detecting what you are asking.
Bear in my playing with the back and forward buttons is a risky task.
window.onload = function () {
if (typeof history.pushState === "function") {
history.pushState("someState", null, null);
window.onpopstate = function () {
history.pushState("newState", null, null);
// Handle the back (or forward) buttons here
// Will not handle refresh, use onbeforeunload for this.
};
}
}
You could use the jquery address plugin (http://www.asual.com/jquery/address/).
It has an event that detects when the user presses the back/forward button.
$.address.externalChange(function() { console.log('back/forward pressed'); });
As far as I know there is no way of differentiating between back and forward.
You should definitely check History.js
Here's some sample code:-
(function(window,undefined){
// Prepare
var History = window.History; // Note: We are using a capital H instead of a lower h
if ( !History.enabled ) {
// History.js is disabled for this browser.
// This is because we can optionally choose to support HTML4 browsers or not.
return false;
}
// Bind to StateChange Event
History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
var State = History.getState(); // Note: We are using History.getState() instead of event.state
//History.log(State.data, State.title, State.url);
var goto_url = State.url;
$.ajax({
url: goto_url,
dataType: "script"
});
});
})(window);