JS window.location in an AJAX based site - javascript

I have a simple AJAX based site that I have an equally simple geolocation function that redirects a user to a new page when they click a button.
This is the part of my geolocation function that redirects users which, as you will see, redirects people to a page called weather.php;
function showPosition(position) {
window.location='weather.php?lat='+position.coords.latitude+'&long='+position.coords.longitude;
}
The problem is that it redirects the page using a "traditional" page load and thus renders the AJAX page loading I have implemented obsolete.
Is it possible to modify this function and make it AJAX friendly?
This is the full redirect code;
<button onclick="getLocation()">My Location</button>
<script>
var x = document.getElementById("message");
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(showPosition, showError);
} else {
x.innerHTML = "Geolocation is not supported by this browser.";
}
}
function showPosition(position) {
window.location='weather.php?lat='+position.coords.latitude+'&long='+position.coords.longitude;
}
<script>

Here is how you can do it.
I give you a simple example of a website where the pages are loaded with Ajax. The page is put in the url.
Not like this: weather.php?lat=50.452
But like this: index.php#50.452
The point is: when you change anything right of the #, the page is not reloaded.
And still, there is a system where the url remembers the page
It's not a complete answer to your question, but I hope it gives you the inspiration you need
pages.php
<?php
switch(isset($_GET['p']) ? $_GET['p'] : '') {
default:
$content = 'This is the HOME page ...';
break;
case 'calendar':
$content = 'calendar stuff ...';
break;
case 'contact':
$content = 'contact stuff ...';
break;
}
echo $content;
?>
index.php
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
// load page according to the url.
// We read the url, to the right hand side of the # (hash symbol)
var hash = window.location.hash;
var page = hash.substr(1); // this removes the first character (the #)
loadPage(page);
// triggered by the navigation.
function loadPage(page) {
getAjaxPage(page);
}
// this returns the content of a page
function getAjaxPage(page) {
switch (page) {
default: // = HOME page
var url = '';
case 'calendar':
case 'contact':
var url = page;
}
$.ajax({
url: 'pages.php',
data: {
p: url
},
success: function(data) {
$('#content').html(data);
}
})
}
</script>
<style>
#content {
margin: 15px;
}
</style>
</head>
<body>
<div id="nav">
Home |
Calendar |
Contact |
</div>
<div id="content"></div>
</body>
</html>
Your job ... You should not redirect the client.
It's (something like) a Google Maps thing, right?
What are your intentions there?
Why can't you load weather.php with Ajax? I bet you can.

Related

session name isnt showing when loading php file

So basically i got this code from online which allows you to load body content via ajax/php.
Site i got the code from:
https://www.webdesignerdepot.com/2014/02/how-to-supercharge-your-sites-speed-with-ajax-and-jquery/
If you look at that site(specifically the ajax/php demo, not the first jquery demo) you'll see that ajax loads load.php, then it loads different html files. Ive edited it to load different php files, however the loaded content displays the html code in my php file but not the php code(session name variable).
Here's the custom.js(ajax) file:
$(function() {
$('.left-sidebar a').click(function() {
var $linkClicked = $(this).attr('href');
document.location.hash = $linkClicked;
var $pageRoot = $linkClicked.replace('#', '');
if (!$(this).hasClass("current")) {
$(".left-sidebar a").removeClass("current");
$(this).addClass("current");
$.ajax({
type: "POST",
url: "load.php",
data: 'page='+$pageRoot,
dataType: "html",
success: function(msg){
if(parseInt(msg)!=0)
{
$('#main-content').html(msg);
$('#main-content section').hide().fadeIn();
}
}
});
}
else {
event.preventDefault();
}
});
var hash = window.location.hash;
hash = hash.replace(/^#/, '');
switch (hash) {
case 'steal' :
$("#" + hash + "-link").trigger("click");
break;
case 'extort' :
$("#" + hash + "-link").trigger("click");
break;
case 'kill' :
$("#" + hash + "-link").trigger("click");
break;
case 'welcome' :
$("#" + hash + "-link").trigger("click");
break;
case 'profile' :
$("#" + hash + "-link").trigger("click");
break;
}
});
here's the load.php file:
<?php
if(!$_POST['page'])
die("0");
$page = $_POST['page'];
// echo $page; // rob, steal, extort, kill, welcome, profile
if(file_exists('pages/'.$page.'.php'))
echo file_get_contents('pages/'.$page.'.php');
else
echo 'There is no such page!';
?>
Here's the welcome.php file:
<?php
if (session_status() === PHP_SESSION_NONE || session_status() !== PHP_SESSION_ACTIVE )
session_start();
print_r($_SESSION);
if (!isset($_SESSION['name'])) {
die(json_encode(array(
"error",
"You must be logged in to view report data."
)));
}
?>
<section id="welcome">
<h2>Welcome Content</h2>
<p class="block">Welcome back, <?=$_SESSION['name']?></p>
</section>
And this is all i see when welcome.php is loaded:
Welcome Content
Welcome back,
After looking at years old post on here a lot of people mentioned needing to have session_start(); at top of file, i tried this and it said "ignoring session start cause a session has already been started".
So i found this on another post where someone else having a similar issue(unfortunately there was no answer for me there[nor for that poster])
<?php
if (session_status() === PHP_SESSION_NONE || session_status() !== PHP_SESSION_ACTIVE )
session_start();
print_r($_SESSION);
if (!isset($_SESSION['name'])) {
die(json_encode(array(
"error",
"You must be logged in to view report data."
)));
}
?>
I put the above code at the very top of welcome.php and when i load welcome.php without ajax i see this:
Array ( [loggedin] => 1 [name] => -Phil (Just-Us) [id] => 1 [role] => Admin )
Welcome Content
Welcome back, -Phil (Just-Us)
But when i load welcome.php via ajax i only see this:
Welcome Content
Welcome back,
UPDATE: So i added the below code to my home.php file of which houses the body content div and said div houses all the dynamically loaded content. And doing this works fine, i see my session name being displayed just fine. So does replacing load.php with welcome.php in the ajax code. So something is going wrong when ajax loads the load.php file and then load.php echo's another php files contents(leaving behind needed php content).
<script>
$(document).ready(
function() {
setInterval(
function() {
$("#main-content").load('pages/welcome.php');
}
, 10000 // 1000ms = 1 second. Lowest i'd go to is 0.05s which is 50ms. (even though the lowest it can go is 4ms apparently. not advised tho)
);
$.ajaxSetup({ cache: false });
}
);
</script>
Why is it that when i use the below code it opens the php file in a new tab rather than loading it into the specified div?
// Create event listener for all link clicks
document.querySelectorAll('page-links').forEach(link => {
link.addEventListener('click', (e) => {
// Retrieve href and store in targetUrl variable
let targetUrl = e.target.href;
// Output value of targetUrl to console
// console.log('A link with target URL ' + targetUrl + 'was clicked');
$("#main-content").load(targetUr);
});
});

passing data using post array in java-script

i am try to load B.php from A.php after execution in the function and pass some data using a post array from A.php to B.php within same time.
code list as follows
A.php
<script type="text/javascript">
alert_for_the_fucntion();
window.location.href = "B.php";
function alert_for_the_fucntion() {
$.post("B.php", {action: 'test'});
}
</script>
B.php
<?php
if (array_key_exists("action", $_POST)) {
if ($_POST['action'] == 'test') {
echo 'ok';
}
}
?>
for testing purpose i tried to echo something in the B.php. but currently this is not working. have i done any mistakes? or is there any possible method to do this.
Your code does this:
Tells the browser to navigate to B.php (using a GET request)
Triggers a POST request using XMLHttpRequest
The POST request probably gets canceled because the browser immediately leaves the page (and the XHR request is asynchronous). If it doesn't, then the response is ignored. Either way, it has no effect.
You then see the result of the GET request (which, obviously, doesn't include $_POST['action']) displayed in the browser window.
If you want to programmatically generate a POST request and display the result as a new page then you need to submit a form.
Don't use location. Don't use XMLHttpRequest (or anything that wraps around it, like $.ajax).
var f = document.createElement("form");
f.method = "POST";
f.action = "B.php";
var i = document.createElement("input");
i.type = "hidden";
i.name = "action";
i.value = "test";
f.appendChild(i);
document.body.appendChild(f);
f.submit();
If you want to process the results in JavaScript then:
Don't navigate to a different page (remove the line using `location)
Add a done handler to the Ajax code
e.g.
$.post("B.php", {action: 'test'}).done(process_response);
function process_response(data) {
document.body.appendChild(
document.createTextNode(data)
);
}
Try this:
Javascript:
<script type="text/javascript">
window.onload = alert_for_the_fucntion;
function alert_for_the_fucntion() {
$.post("B.php",
{
action: 'test'
},
function(data, status){
if(status=="success"){
alert(data);
}
}
);
}
</script>
PHP
<?php
if(isset($_POST['action'])){
echo $_POST['action'];
}
?>

how to store state using in sinatra using json/javascript without databases

The html view of the app contains a variable which is by default set to 20. This temperature is then increased or decreased using a up/down button when running the app in the browser. However if the browser or page is refreshed (or redirected) temperature does not remain but instead always resets to 20.
Here is the view:
<!DOCTYPE html> <link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'> <html> <head>
<link rel="stylesheet" type="text/css" href="style.css"> </head> <body>
<section class="display">
<h1>Thermostat</h1>
<input id='city' type='text' placeholder="city name">
<button id='submit'>Submit</button>
<p id='weather'></p>
<h1 id="temperature"></h1>
<h4 id="psm"></h4>
<form action='/temperature' method='post'>
<button class="icon icon-up" id="up" name='temp'></button>
<button class="icon icon-down"id="down" name='temp'></button>
<button id="reset" name='temp'>reset</button>
<button id="switchpowersaving">PSM</button>
</form>
</section>
<script src="jquery.js"></script>
<script src="thermostat.js"></script>
<script src="interface.js"></script>
<script src="weatherAPI.js"></script> </body> </html>
When we visit the page we are directed to the index. Here we then increase/decrease the temperature. Every time temperature is changed a 'POST' method is sent to our /temperature page. This then creates a hash using JSON, sessions and parameters. This in the interface.js file there is an ajax GET function which stores this new temperature as data.temp. This should then set the thermostat.temperature to the stored data.temp everytime the page is reloaded. However it continually gets reset to 20.
This is the controller:
require 'sinatra'
require 'json'
enable :sessions
get '/' do
send_file 'views/index.html'
end
post '/temperature' do
p params[:temp]
session[:temp] = params[:temp].to_i
redirect '/temperature'
end
get '/temperature' do
p session[:temp]
if session[:temp]
JSON.generate({temp: session[:temp]})
else
JSON.generate({temp: 20})
end
redirect '/'
end
Here is the interface.js file:
$(document).ready(function() {
var thermostat = new Thermostat();
var temp = thermostat.temperature;
$.ajax({
type: 'GET',
url: 'http://localhost:4567/temperature',
success: function(data){
temp = data.temp;
},
error: function(){
alert('Error loading temp');
}
});
updateTemperature();
$('#up').click(function() {
thermostat.increaseTemperature();
updateTemperature();
});
$('#down').click(function() {
thermostat.decreaseTemperature();
updateTemperature();
});
$('#reset').click(function() {
thermostat.tempReset();
updateTemperature();
});
$('#switchpowersaving').click(function() {
thermostat.switchModePowerSaving();
updateTemperature();
});
function updateTemperature() {
$('#temperature').text(thermostat.currentTemperature() + "\xB0C");
$('#up').attr('value', thermostat.currentTemperature());
$('#down').attr('value', thermostat.currentTemperature());
$('#reset').attr('value', thermostat.currentTemperature());
$('.display').css('background-color', thermostat.displayColor());
$('#psm').text(thermostat.displayPowerSaveMode());
}
});
Here is the thermostat.js :
function Thermostat(){
this.temperature = 20;
this.MINTEMP = 10;
this.isPowerSaving = true;
this.thermostatDisplay = 'yellow';
}
Thermostat.prototype.currentTemperature = function(){
return this.temperature;
};
Thermostat.prototype.increaseTemperature = function(){
if ( this.currentTemperature() >= this.maxTemp()) {
throw 'Max. temp reached';
}
this.temperature ++;
};
Thermostat.prototype.decreaseTemperature = function(){
if ( this.currentTemperature() <= this.MINTEMP ) {
throw 'Min. temp reached';
}
this.temperature --;
};
Thermostat.prototype.maxTemp = function(){
if(this.isPowerSaving === true) {return 25;}
else
{return 32;}
};
Thermostat.prototype.switchModePowerSaving = function() {
if (this.isPowerSaving === true)
{this.isPowerSaving=false;}
else
{this.isPowerSaving=true;}
};
Thermostat.prototype.tempReset = function() {
this.temperature = 20;
};
Thermostat.prototype.displayColor = function() {
if(this.temperature <= 18) {return 'green';}
if(this.temperature <= 25) {return 'yellow';}
if(this.temperature > 25) {return 'red';}
};
Thermostat.prototype.displayPowerSaveMode = function(){
if(this.isPowerSaving === true) {return 'Power Save Mode: ON';}
else {return 'Power Save Mode: OFF';}
};
The increaseTemperature/decreaseTemperature functions simply increase and decrease thermostat.temperature by +1/-1.
The new temperature when the button is pressed can be accessed when directly accessing '/temperature' in the browser however when redirected to the '/' the new thermostat.temperature is not set to the new temperature and always resets to the default temperature (20).
How can this be stored in state without using databases. (Store the new temperature so when the page is refreshed the new temperature remains rather than resetting to 20.
A couple of issues here:
send_file is not the preferred way of loading a HTML file using Sinatra. The alternative to this is to rename the index.html to index.erb and then use the following as the route descriptor:
get '/' do
erb :index
end
ERB is a superset of HTML and adds ruby interpolation tags that can be used to pass variables from Sinatra or simply run ruby commands in the view. These tags are similar to JSP's <%%> or PHP's <?php ?> if you're familiar with those. In ERB, <%%> would run a ruby command, <%= %> can be used to print out the result of a ruby command onto the view.
It's important to figure out the data type of request/response upfront while designing the routes. For instance, when interface.js loads, it makes a GET request via jQuery to the '/temperature endpoint. Since you haven't specified the data type, the response would be a string and data.temp will be null. So in the ajax call, you'd need to add a dataType: 'json' setting:
$.ajax({
type: 'GET',
url: 'http://localhost:4567/temperature',
dataType: 'json',
success: function(data){
// same as earlier
});
One more good thing to do is not to mix and match AJAX calls and redirect calls in sinatra. This is a problem especially in this case because when you redirect to the index page, although the session data is present, it's not getting loaded/displayed anywhere. Ideally, in Sinatra you'd have to assign the value to an instance variable and print it out in the view:
# app.rb
get '/' do
#temp = session[:temp] || 20
erb :index
end
# views/index.erb
# truncating common code
<h1 id="temperature"><%= #temp %></h1>
That way, when the get '/' route loads, initial temperature is displayed. The $.ajax GET request can be removed entirely.
When buttons are clicked, by default the form submit happens which will do a full reload. This can mess up with any JS based rendering you are doing (I'm unable to understand that part entirely for now). So instead of doing a full page redirect, it's better to an AJAX post (like pointed out in the comments) to '/temperature' route. Note that you'd have to disable the default action of a button click. So:
$('#up').click(function() {
thermostat.increaseTemperature();
updateTemperature();
});
and other click handlers should be changed to:
$('#up').click(function(event) {
event.preventDefault();
event.stopPropagation();
thermostat.increaseTemperature();
updateTemperature();
});
This will ensure that the default HTML form submit doesn't happen when you click on the button. And updateTemperature() will make an ajax POST call. I've put up a sample here: https://gist.github.com/kgrz/9320d1682e682a9930c30e34c979a306

Passing parameters while Linking to another html page in google apps script

First, this is a google-app-script issue... I can't seem to capture the second (or subsequent) parameters within the HTML page (i.e. "item" in this example)... I've seen many examples using "location.search" and "window.location.search", but none of these seem to work. Could it possibly be as simple as "location.search" is not the correct usage?
Example
Code.gs
var myParam;
/**
* Get the URL for the Google Apps Script running as a WebApp.
*/
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
/**
* Get "home page", or a requested page.
* Expects a 'page' parameter in querystring.
*
* #param {event} e Event passed to doGet, with querystring
* #returns {String/html} Html to be served
*/
function doGet(e) {
//Logger.log( Utilities.jsonStringify(e) );
Logger.log(e.parameter.page);
var pgToLoad = e.parameter.page;
if (!e.parameter.page) {
Logger.log('!e.parameter.page')
// When no specific page requested, return "home page"
// return HtmlService.createTemplateFromFile('my1').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
return HtmlService.createTemplateFromFile('my1').evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
Logger.log('there is something for the page');
// else, use page parameter to pick an html file from the script
// return HtmlService.createTemplateFromFile(pgToLoad).evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
return HtmlService.createTemplateFromFile(pgToLoad).evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
I have multiple HTML files, but they are basically the same as my1.html below...
my1.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
</head>
<body>
<h1>Source = my1.html</h1>
<p id=myParam>Placeholder</p>
<?var url = getScriptUrl();?><a href='<?=url?>?page=my2&item=1-234'> <input type='button' name='button' value='my2.html'></a>
<?var url = getScriptUrl();?><a href='<?=url?>?page=my3&item=1-345'> <input type='button' name='button' value='my3.html'></a>
</body>
</html>
<script>
function getParam(sname)
{
var params = location.search;
var sval = "";
params = params.split("&");
// split param and value into individual pieces
for (var i=0; i<params.length; i++)
{
temp = params[i].split("=");
if ( temp[0] == sname ) { sval = temp[1]; }
}
return sval;
}
function changeItem() {
var param = getParam("item");
var myItem = "Item:-"+param+"-";
document.getElementById("myParam").innerHTML = myItem;
}
window.onload = changeItem;
</script>
I think I know what you want to do. It looks like you are getting the search string parameters from the doGet(e) function on the server side, then you are trying to get the same search string parameters again on the "client side" from the onload function? If this is the case, I would abandon trying to get the search string parameters from the client side.
You could store the search string parameters in the browsers sessionStorage:
window.sessionStorage.setItem("searchStringOne","Value One");
and to retrieve:
var valueOne = window.sessionStorage.getItem("searchStringOne");
Session Storage Information
Here's an example to show how to get the query string parameters to serve different html templates using html-service of app script :
function doGet(e) {
Logger.log( Utilities.jsonStringify(e) );
// Load a home page when no parameter is specified
if (!e.parameter.redirect) {
var template = HtmlService.createTemplateFromFile('home');
var htmlOutput = template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle('Home');
return htmlOutput;
}
//get the page from parameter and load it
else{
var template=HtmlService.createTemplateFromFile(e.parameter['redirect']);
var htmlOutput = template.evaluate().setSandboxMode(HtmlService.SandboxMode.IFRAME).setTitle('Other Page');
return htmlOutput;
}
}
function getScriptUrl() {
var url = ScriptApp.getService().getUrl();
return url;
}
then HTML will look like this :
home.html
<?var url = getScriptUrl();?>
You are on Home Page.
<a href='<?=url?>?redirect=pagex'>Goto PageX</a>
<a href='<?=url?>?redirect=pagey'>Goto PageY</a>
pagex.html
You are on PageX
pagey.html
You are on PageY
Hope this helps!

History API, refresh and bookmark

pushState doesn't make a request, it just changes the url and stores a new history entry. Thinking about this concept, it's impossible to refresh or bookmark because the server will always do a request. A server-side solution is needed.
After several hours searching, I have found a solution, every single call must be redirect to index.php to let PHP handle the request.
rewrite ^/(.*)$ /index.php?page=$1 last
I don't know exactly how this file should be to let a website refresh or bookmark a page. Can somebody help me ? I made an example to help clarify.
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<title>History API</title>
<script>
function ajax (url, callback) {
var conection = new XMLHttpRequest ();
conection.open ("GET", url, true);
conection.setRequestHeader ("X-Requested-With", "XMLHttpRequest");
conection.send (null);
conection.onreadystatechange = function () {
if (conection.readyState === 4) {
if (conection.status === 200) {
callback (conection.responseText);
}
else if (conection.status === 404) {
alert ("Page not found !");
}
else {
alert ("Error !");
}
}
}
}
window.addEventListener ("popstate", function (event) {
var state = event.state;
if (state) {
document.getElementById ("content").innerHTML = state["content"];
}
});
document.addEventListener ("DOMContentLoaded", function () {
var content = document.getElementById ("content");
var menu = document.getElementById ("menu");
menu.addEventListener ("click", function (event) {
var target = event.target;
if (target.nodeName === "A") {
ajax (target.href, function (result) {
history.pushState ({"content": result}, target.innerHTML, target.href);
content.innerHTML = result;
});
event.preventDefault ();
}
});
});
</script>
<style>
body {
width: 400px;
}
div {
border: 1px solid black;
padding: 10px;
}
</style>
</head>
<body>
<div id = "menu">
Page 1
Page 2
</div>
<div id = "content"></div>
</body>
</html>
index.php
<?php
isset ($_GET["page"]) or exit ("Error !");
$page = $_GET["page"];
// Ajax request
if (isset ($_SERVER["HTTP_X_REQUESTED_WITH"]) && strtolower ($_SERVER["HTTP_X_REQUESTED_WITH"]) === "xmlhttprequest") {
if (file_exists ($page)) {
require_once ($page);
}
else {
header ("HTTP/1.1 404 Not Found");
}
}
else {
require_once ("index.html");
}
?>
page1.html
Hello, I'm the Page 1. It's nice to meet you.
page2.html
Hi brother. I'm page 2.
Clicking (ok)
Refresh (fails)
First of all you should really not use a GET parameter as input for a _require_once_. Really. Not. Use at least a simple whitelist of allowed names for pages and only include and output mapped files (or files with those whitelisted names).
Now to your history API problem. Pushing things obviously seems to work for you so all that is missing is probably a simple ondomready event that reads the current URL and loads the content via AJAX or from existing history entries. The same whitelist approach should be used there. Also try to not fall into the trap of DOMXSS by using unvalidated input (the URL) as input for your javascript and DOM operations.

Categories

Resources